LoginSignup
1
0

More than 3 years have passed since last update.

Pedestalでレスポンスの文字コードを任意に指定するだけのインターセプター

Last updated at Posted at 2019-11-04

概要

Duct + PedestalでAPIサーバを作っていると、JSONを返すためにpedestal.http/json-bodyインターセプターを使いたくなる。

なおこのjson-bodyくん、親切にも Content-Typeに文字コードUTF-8を指定しているため、レスポンスが実際には Shift-JISだとしても問答無用でUTF-8を指定して返す
日本語が文字化けする😇

考えあぐねた結果 レスポンスのContent-Type部分で文字コードだけを狙い撃つように変えるインターセプターを作った。色々アレな発想だが切羽詰まっていたので許してほしい。ごめんて。

※ 文字化け問題はJVMが原因だとわかったので、こっちでスッと解決できた => https://qiita.com/v2okimochi/items/40d0ebd2186657a44969

ソースコード

たとえば v2okimochi-apiという名前空間で interceptors.cljに当該処理を書いておき、これを呼び出して使う。

インターセプター

interceptors.clj
(ns v2okimochi-api.interceptors
  (:require [io.pedestal.interceptor.helpers :as interceptor]
            [ring.util.response :as ring-response]))

(defn set-charset
  "responseを任意の文字コードに変換する"
  [charset]
  (interceptor/on-response
   ::set-charset
   (fn [response]
     (let [content-type (get-in response [:headers "Content-Type"])]
       (cond

         ;; `charset=`以降を変換する
         (and (string? content-type)
              (re-matches #".*charset=.*" content-type))
         (->> (clojure.string/replace content-type #"(\.*charset=).*"
                                      (str "$1" charset))
              (ring-response/content-type response))

         ;; `Content-Type`に文字コード指定を追加する
         (string? content-type)
         (->> (str content-type ";charset=" charset)
              (ring-response/content-type response))

         ;; 文字コード指定で `Content-Type`を作る
         :else
         (ring-response/content-type response (str "charset=" charset)))))))

\ ))))))) /

ルーティング

たとえばこうやって使う。

routes.clj
(ns v2okimochi-api.routes
  (:require [integrant.core :as ig]
            [io.pedestal.http :as http]
            [io.pedestal.http.body-params :as body-params]
            [io.pedestal.http.route :as route]
            [v2okimochi-api.handler.sample-responses :as sample] ; これは自作
            [v2okimochi-api.interceptors :as interceptors])) ; これも自作

;; 文字列を変数に押し込んだだけです
(def charset-shift-jis "shift-jis")
(def charset-utf-8 "utf-8")

(defmethod ig/init-key ::routes
  [_ options]
  (let [common-interceptors [(interceptors/set-charset charset-shift-jis)
                             http/json-body]]
    #(route/expand-routes
      #{["/okimochi" :get
         (conj common-interceptors `sample/okimochi-response)]})))
  • これはレスポンスをJSON変換して返すだけのやつ
  • set-charsetをjson-bodyの上に差し込むことで、JSON変換されたレスポンスの文字コード部分だけを変える(この場合はShift-JISになる)
  • set-charsetでは 文字コードが既に指定されている場合Content-Typeはあるが文字コード指定が無い場合Content-Typeすら無い場合(たぶん)に合わせて文字コードを狙い撃つ

まとめ

  • 文字コードを変えるだけ
  • 頑張らなくても良かった()
  • インターセプターチョットワカッタ
  • 文字コード変換系、需要無いのかな。。。
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0