Servletの文字化け
今更ながら、javax.servlet.ServletRequestクラスの
getParameterメソッドで日本語を取得したときの文字化けについてメモ。
専門学校生を教えてる中でいろいろ質問が出たので。
通常は、何もやらずにいきなり日本語を取得すると
文字化けしちゃいます。理由は以下の通り。
1) ブラウザのFORMで「あいう」と入力して送信
2) 送信時の「あいう」の文字コードは0x82A0、0x82A2、0x82A4(Shift_JISの場合)
3) Servletに渡る際は、上位に00がついてしまう(0x0082、0x00A0、0x0082、0x00A2・・・)
そこで、値を取得した後に以下のコードを記述すると・・・
String str = request.getParameter("param"); byte[] bytes = str.getBytes("iso-8859-1"); str = new String(bytes, "Windows-31J");
4) str.getBytes("iso-8859-1")によりバイト配列に変換(0x82、0xA0、0x82、0xA2・・・)
5) new String(bytes, "Windows-31J")により、バイト配列を元に正しいUnicodeの「あいう」を生成
5)で指定したWindows-31Jは、元のデータがShift_JISであったことを指定してます。
Windows-31Jに関してはこちら。
これで正しく日本語を取得できます。
ここまではJ2EE1.2(Sevlet2.2)の話。
J2EE1.3(Servlet2.3)からは、javax.servlet.ServletRequestクラスの
setCharacterEncodingメソッドで、上記の処理をしてくれます。
使用例はこんな感じ。
request.setCharacterEncoding("Windows-31J"); String str = request.getParameter("param");
現在市販されてるAPサーバはほとんどがJ2EE1.3以上なので、
古い環境を利用するんじゃなければこっちの方がいいかと。
ただし、setCharacterEncodingメソッドは
リクエストのボディに対して適用されるとありますが、
リクエストヘッダに対しては明確な仕様が存在してないそうです。
そこで、Tomcatの場合は4.1.29/5.0.16からsetCharacterEncodingメソッドの
指定はヘッダに対しては適用されなくなりました。
ヘッダに対して(つまりGETで日本語を渡したとき)も適用したい場合は、
server.xmlのConnectorタグのuseBodyEncodingForURI属性を
trueにする必要があるようです。
ちなみにTomcat4.1.x系はデフォルトがtrue、5.0.x系はfalse。
(でももしかしたら一部デフォルトが違うのがあるかも?)
う〜ん、ほんとにややこしい。。。
とりあえずTomcatを利用する際はserver.xmlの記述を確認しろと。
他のAPサーバの状況については、id:hyperash:20040309さんが説明されてました。
うちはJRunを利用してるのでそのうち調べとかなきゃ。
んでも一番重要なのは、クライアントが何の文字コードで
日本語を送ってきてるのか・・・だよなぁ。
WindowsならShift_JIS、LinuxならEUC-JP・・・かと思いきや、
LinuxからShift_JISで送信することもできてたし。
っていうか、User-Agent自体いくらでも偽装できるから
そっから正しい文字コードを取得するって考え自体無理。
JavaHouseでは、文字コードの判別ができる適当な文字を
hiddenの入力項目に必ず用意するって案を出してる人がいたなぁ。
これは確かに有効かも。ちょいかっこわるいけど。
ログイン時だけこれで判定して、以降は判定結果を
格納したセッションかCookieを利用すればいいのかな。
うちは特定ユーザを対象にした業務アプリがメインだから
制限にしちゃえばいいんだけど、インターネット環境の
アプリを開発してる人たちはどうやってるんだろうなぁ。。。
新人の頃からこの辺の問題は何も解決してない気がする。
何か間違ったことを書いていたらご指摘くださいm(_ _)m