要点
- Play framework 2.3.xと
UTF-8
について解説します Shift_JIS
でパーセントエンコードされたデータを扱う事の困難性を解説します- 実際にPlay framework 2.3.xで上記のデータを受け取る方法について解説します
Play frameworkとUTF-8
Play framework 2.3.x(Scala)は、UTF-8
を標準的なcharsetとして扱っている*1。特にパーセントエンコーディングされたデータがGET
/POST
メソッドで渡って来るときは、Content-Type
ヘッダでcharsetを指定しなければUTF-8
であるものとしてデコードされる*2。
PlayでShift_JISを扱う困難さ
Shift_JIS
を扱うようなアプリケーション*3では、フォームの入力などとして渡って来たデータをUTF-8
ではなくShift_JIS
としてデコードしたい局面が多々ある。しかしながらクライアントの行儀が悪いためにContent-Types: application/x-www-form-urlencoded; charset=Shift_JIS
のようにきちんとcharsetを指定せずにContent-Types: application/x-www-form-urlencoded
とだけ記載されたデータがPlayに渡ってくる。例えば、ほとんどの2ちゃんねるブラウザ(以下、「専ブラ」)はcharsetを指定せずにデータを送信してくる。
Charsetを指定せずにPlayにShift_JIS
でパーセントエンコーディングされたデータを渡したらどうなるか。やはりUTF-8
としてデコードされ、無残にも?????
のような文字列となってコントローラに渡ってくる。コントローラに到達した時点でフォームパラメータは、パーセントエンコーディングが規定の(ここではUTF-8
)charsetでデコードされ、Map[String, Seq[String]]
としてパースされた状態となっている。
またデコードは不可逆であり、一度UTF-8
でデコードして得られる文字列をArray[Byte]
に型変換してからもう一度Shift_JIS
としてデコードすることはできない。
このため、charsetを指定しないクライアントからShift_JIS
でフォームが送信された場合、これを正しくデコードするのは困難だ。正しく処理するために採ることができる選択肢は:
- Play frameworkのソースを修正してリビルドする
- パーセントエンコーディングのパーサーにかかる前にリクエストのヘッダを修正する
- 生の文字列としてリクエストを受け取り、手動で
Shift_JIS
としてパースする
1: Play frameworkのソースを修正してリビルドする
そもそもPlay frameworkのソースを修正してリビルドすれば自分の好みの動作をさせることができる。だがこの場合は環境構築に多大な手間を要することになるし、バージョンアップに追従しなければならない。このコストはあまりに大きいのでボツ。
2: パーセントエンコーディングのパーサーにかかる前にリクエストのヘッダを修正する
かつて僕はこのアプローチを採ろうとしたが失敗した。ヘッダを書き換えることでcharsetを指定しても、Playは正しくデコードしてくれなかった。僕の方法がまずかったかもしれないが、できないものはできないのでボツ。
3: 生の文字列としてリクエストを受け取り、手動でShift_JIS
としてパースする
最終的に僕が辿り着いたのがこのアプローチだ。コントローラはひとまずリクエストボディを生の文字列として受け取り、オリジナルのパーサに処理させてリクエストを作りなおし、本来のリクエストとすげ変える。次項ではこれについて解説する。
Play framework 2.3.xでShift_JISのボディを処理する
まずはコードを見てほしい。
Play 2.3.x でShift_JISのパーセントエンコーディングされたデータを受け取る
ソースコードのポイントは、Action
の引数にparse.tolerantText
を指定することで、bodyを生のString
としてパースしてもらう事だ。これによりPlayは自動的にUTF-8
のフォームデータとしてbodyをパースしなくなるので、手動でbodyをパースすることができる。Action
の引数を省略すると、Action (parse.anyContent) {...}
が指定されているのと同じになる。anyContent
は、自動的にbodyの内容からパーサーを決めてくれる。この場合ならurlFormEncoded
が呼び出されるだろう。
ちなみにplay.api.mvc.BodyParsers.parse
には、ファイルやXMLなどのデータを自動的に処理してコントローラに送るための様々なパーサーが用意されているので見ておくと良い。
まとめ
Shift_JISは絶滅してほしい。これを解決するのにものすごい時間がかかったので後学のためにメモしておきます。お行儀の良いクライアントが増えますように。