TomcatのURLパラメータ文字化け

ちと古い話題ですが。。。

Request#setCharactorEncoding()がかかるのはBODYだけ

URLのリンクはよくURLEncodeしてわたしたりします(こんな感じ↓)

<a href=hoge.html?prm=%82%A0%82%A0%82%A0">

昔は大丈夫だったんですが、どこかのバージョンのTomcatから、

Request#setCharactorEncoding()は、HTMLのボディ部だけに適用され、URLリクエスト内にはかからない


という実装(仕様どおりの正しい実装)になってしまったようです。


[Ja-Jakarta ML]Servlet, JSP関連の問題点
http://www.jajakarta.org/ml/general/200402.month/1865.html



また、TomcatのURLパラメータのデコード文字コードは「デフォルトで、ISO-8859-1」になっており、日本語パラメータをUTF-8Windows-31Jなどでエンコードしても、ISO-8859-1で復元されちゃって、正しく復元できません(request.getParameter()した時点ですでに原型をとどめてない)。

setCharactorEncoding()をしてて、POSTは大丈夫なのに、GETで文字化け
(というかURLに?つきでわたしたのだけ文字化け)


という場合はこのあたりに原因があるかもしれません。
URLパラメータは、これまで、英数字のなんとかIDとかしか渡してなかったので、
特に困ることはなかったから、これまであまり気にしてませんでした。。。

対処法

これの解決法として以下の方法があるようです。


http://d.hatena.ne.jp/hyperash/20040428

Tomcat 5(5.0.16以降)では、server.xmlのConnecter定義の中でuseBodyEncodingForURIをtrueに設定するか、SetCharacterEncodingFilterを修正する。


useBodyEncodingForURIは、こんな感じ。
(他に、URIEncoding要素でURL部分のエンコードを指定することもできる)

useBodyEncodingForURI="true"
/>

参考 http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/http.html


この方法が簡単。ただし、コンテナ単位の設定になり、他のWebアプリにも影響するのがちょっとイヤなかんじかも。


もう1つのフィルターを使う方法は、例えば、request#getQuerryString()をひっぱってきて、自分で解析という感じだろうか。しかし、サーブレットAPIでは、POST、GET、URLパラメータかどうかなどを隠蔽して作られたAPIなので、それをまた自分で判別してどうこうするってのもどーかなーという気もする。


追記:例えばこんなかんじか?

フィルタ


package ws.miya.web;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class EncodeFilter implements Filter{

private String enc;

public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException, ServletException {

req.setCharacterEncoding(enc);
req = new PortableRequestWrapper((HttpServletRequest)req, enc);

chain.doFilter(req, res);
}

public void init(FilterConfig config) throws ServletException {
enc = config.getInitParameter("enc");
}

public void destroy() {
}
}

リクエストラッパ


package ws.miya.web;

import java.net.URLDecoder;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class PortableRequestWrapper extends HttpServletRequestWrapper{

private Properties urlParameters;

public PortableRequestWrapper(HttpServletRequest request, String encode) {
super(request);
urlParameters = parseQuerry(request, encode);
}

private Properties parseQuerry(HttpServletRequest request, String encode){

Properties prop = new Properties();
String query = request.getQueryString();

if(query == null || query.length() == 0){
return prop;
}

try{
String[] ss = query.split("\\&");

for(int i=0; i


その他の対処(逃げ?)としてはこんなのか。

  • URLパラメータにマルチバイトをわたさない
  • POSTでわたす
  • マルチバイトをわたしたものについては、自分でgetQueryStringして展開