AjaxとシフトJIS

全体の文字コードシフトJIS(Javaでは"Windows-31J")で統一しているWebアプリケーションで、部分的にExt.js(に限らずAjax)を使おうとするとAjax通信部分のデータはUTF-8にする必要があるため文字コードの部分でつまづくことが多いです。

サーバからのレスポンスについては、UTF-8に変換して返せばよいのですが、クライアントで入力されたデータをAjaxでサーバ再度に送信するような場合には(例えばPrototype.jsのForm.serializeのような)、データはUTF-8で送信されてきます。
そのためサーバ側で受信したデータが文字化けしてしまって困ってました。文字コードを変換してもうまくいかずにしばらく悩んでいたのですが、Servletでの文字コードの設定に問題があることにやっと気づきました。

StrutsなどServletを使ったシステムでは、文字コードの設定をサーブレットフィルタを使って、こんな感じで行うことが多いと思います。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
        if (encoding != null) // encodingは"Windows-31J"
            request.setCharacterEncoding(encoding);
        }

        chain.doFilter(request, response);
    }

これだと、通常のフォームのサブミットでもAjaxからのリクエストでも一緒くたにしてWidows-31Jとして扱ってしまいます。これでは、そのあといくら文字コードを変換してみてもうまくいかないわけです。。以下の様にAjaxのリクエストのみUTF-8として扱うことで文字化けしないでデータを受け取る事ができました。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
        if(((HttpServletRequest)request).getHeader("X-Requested-With") != null){
            request.setCharacterEncoding("UTF-8");
        }
        elseif (encoding != null) // encodingは"Windows-31J"
            request.setCharacterEncoding(encoding);
        }

        chain.doFilter(request, response);
    }

新しく開発するシステムであれば全体でUTF-8を使うのがよいのですが、既存のシステムで文字コードを変更するのは結構つらいのでとりあえずの回避策ということでした。