13100


こんにちは。

先日、本番運用しているシステムにて、システム修正したところ、全角の文字が文字化けを起こす、という障害となりました。  
前日行った修正としては、log4jのログにセッション情報と利用者IDを出力するようにfilterプログラムを追加しています。

【環境】  
OS：CentOS release 6.5 (Final)  
tomcat:6.0.39  
apache:2.2.21  
java:1.7.0_45

【filterプログラム】

[code]

    package util;
    
    import java.io.IOException;
    import java.util.Enumeration;
    
    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;
    import javax.servlet.http.HttpSession;
    
    import org.apache.log4j.NDC;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    public final class NdcFilter implements Filter  {
    
    
        private static final Logger logger = LoggerFactory.getLogger(NdcFilter.class);
        private FilterConfig filterConfig = null;
    
        public void destroy() {
            this.filterConfig = null;
        }
    
        public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
            if (filterConfig == null) {
                return;
            }
    
            if (request instanceof HttpServletRequest) {
                HttpServletRequest req = (HttpServletRequest) request;
    
                HttpSession session = req.getSession();
    
                //if (session== null) {
    
                   Enumeration e = req.getParameterNames();
    
                   while(e.hasMoreElements()) {
                            String key = (String)e.nextElement();
    
                            //logger.debug(key + "：" + req.getParameter(key));
    
                            if ( (key.equals("loginId")) || (key.equals("U"))){
    
                                session.setAttribute("loginId_log4j", req.getParameter(key));
                                logger.debug((String)session.getAttribute("loginId_log4j"));
                                break;
                            }
    
                  }
                //}
                NDC.push(req.getSession().getId() + " " + (String)session.getAttribute("loginId_log4j"));
    
                try {
                    chain.doFilter(request, response);
                } finally {
                    NDC.remove();
                }
            }
        }
    
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
        }
    
    
    }
    
[/code]

【web.xml】（抜粋）

[code]

    <filter>
        <filter-name>encodingfilter</filter-name>
        <filter-class>org.seasar.extension.filter.EncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>Windows-31J</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>NDCfilter</filter-name>
        <filter-class>util.NdcFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>NDCfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>encodingfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
[/code]

文字化けの原因はおそらく「encodingfilter」の前に「NDCfilter」を設定したことで、すべてのプログラムの動作がデフォルトのエンコードとなってしまったものと考えています。  
（実際に、web.xmlのfilterの順番を逆にしたら文字化けは発生しませんでした。）

そこで、いくつか質問があります。  
①文字化けの原因は、私の考える通りであっていますでしょうか？  
②デフォルトのエンコードは、そもそもどのように決められるのでしょうか？

①については、皆様のご意見を、②については、手掛かりとなる情報ソースなどあればご紹介いただくと幸いです。

よろしくお願いします。


CC BY-SA 3.0
2015-08-06T06:23:13.030
13098
2015-08-06T06:45:53.457
10349
question
java linux tomcat
java　filterプログラム追加での文字化け対応について


①あっています。  
Filterはweb.xmlに定義した順に呼び出されます。「encodingfilter」の前に「NDCfilter」を設定すると、encodingfilterにてエンコーディングを設定するより前にNDCfilterにてパラメータの値を取り出してしまうため、デフォルトのエンコーディングを使用してしまい文字化けするという結果となります。

②デフォルトのエンコーディングは、TomcatではGETの場合「US-
ASCII」、POSTの場合「ISO-8859-1」です。GETはサーブレットの仕様には定義されておらず、Tomcatなど各サーブレットコンテナの実装に委ねられています。POSTはサーブレットの仕様に定義されており、リクエストボディのエンコーディングは「ISO-8859-1」です。

> Default encoding for GET  
>  （中略）The character set is defined to be US-ASCII
>
> Default Encoding for POST  
>  ISO-8859-1 is defined as the default character set for HTTP request and
> response bodies  
>  <http://wiki.apache.org/tomcat/FAQ/CharacterEncoding>

最新のサーブレットである3.1の仕様書にも以下のような記述があります。

> 3.11 Request data encoding  
>  The default encoding of a request the container uses to create the  
>  request reader and parse POST data must be “ISO-8859-1” if none has been
> specified by the client request.  
>  <http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-
> spec/index.html>

なお、US-ASCIIとISO-8859-1はほぼ互換があるため、US-ASCIIはISO-8859-1として考えても問題ありません。


CC BY-SA 3.0
2015-08-06T06:45:53.457
13100
2015-08-06T06:45:53.457
4464
13098
answer