2007 年 4 月 10 日 23 時 57 分

HttpServletRequest#getParameter の調査


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


どうも getParameter 系の挙動があやしそうだ。

Struts はフォームからのデータの読み取りに、
getParameter 系のメソッドを利用しているため、
getInputStream や getReader が呼び出されることはない。

そこで HttpServletRequest#getParameter を調べてみよう。

UpdateFilterInfoAction#execute 内に以下のように書く。

    String note = request.getParameter("info.note");
    if (note != null) {
        System.err.println("Encoding: "
                + request.getCharacterEncoding());
        System.err.println("Note: " + note);
        System.err.println("Length: " + note.length());
    }

コンソール又は Tomcat のエラーログを見てみると、
見事に文字化けしていることが分かる。

Encoding: null
Note: ??????????????£??≪???
Length: 21

この結果から分かることは以下のとおりだ。

クライアントが文字エンコーディングを送信していないので、
Servlet は既定の ISO-8859-1 でパラメータを解釈した。

送信した文字列は「内向きフィルタ」7 文字であるが、
これを UTF-8 としてバイト配列にすると 21 バイトになり、それを ISO-8859-1 として文字に戻すと 21 文字となる。

UTF-8 のバイト表現を ISO-8859-1 として解釈したため、
バイトと文字の対応付けがおかしくなり文字が化けた。

さて、一見クライアントの責任のようにも読み取れるが、
この場合、クライアントには責任はない。

getCharacterEncoding() で有効な値を読み出せるのは、
クライアントが Content-Type に追加パラメータとして、
charset パラメータを送信したときである。

これは、例えば以下のような Content-Type が相当する。

    Content-Type: text/html; charset=Shift_JIS

charset パラメータは、文字に関する情報なので、
通常メディアタイプが text/* の場合にしか使われない。

フォームは application/x-www-form-urlencoded なので、
「application」タイプである。
この場合、パラメータの指定は強制されない。

寧ろ、application/x-www-form-urlencoded を定めている、
HTML の規格上でパラメータについて言及されていない以上、
クライアントが charset パラメータを送信するわけがない。

では、文字化けを防ぐにはどうすれば良いか。

簡単に言えば、文字エンコーディングを変えれば良いのだ。
幸い、HttpServletRequest には、
setCharacterEncoding という setter が用意されており、
文字エンコーディングを変更することができる。

このメソッドを呼び出して UTF-8 を指定すれば、
getParameter でデータを読み出した際に、
文字化けを防ぐことができるのである。

ただし、setCharacterEncoding を使う場合、
getParameter や getReader 等のメソッドを呼ぶ前に、
setCharacterEncoding を呼ばなければならない制約がある。

それなら、関連付けられている Action の、
execute メソッドの最初で呼べばと考えそうだが、
残念ながらこれでは上手くいかない。

なぜならば、Action が呼ばれる前に、
Struts によって ActionForm が初期化されるからだ。
Struts が ActionForm に値を設定する際には、
HttpServletRequest の getParameter 系メソッドを呼ぶ。

そのため、Action で setCharacterEncoding を呼んでも、
時すでに遅し。ActionForm には化けた値が入っているのだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.