概要
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すら無い場合(たぶん)
に合わせて文字コードを狙い撃つ
まとめ
- 文字コードを変えるだけ
- 頑張らなくても良かった()
- インターセプターチョットワカッタ
- 文字コード変換系、需要無いのかな。。。