为应用添加一个 CharsetFilter 是极其普通的事情,做的事情无非是 request.setCharseterEncoding(xxx),如果需要,response可能也会动动。
如此简单,依然出了乱码问题。看代码:

 1     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
 2         log.info("response.isCommitted() => " + response.isCommitted());
 3         if (response.isCommitted()) {
 4             HttpServletRequest req = (HttpServletRequest) request;
 5             HttpServletResponse resp = (HttpServletResponse) response;
 6             Cookie[] cks = req.getCookies();
 7             for (int i = 0; cks != null && i < cks.length; i++) {
 8                 log.info("cookie:\t" + cks[i].getName() + " => " + cks[i].getValue());
 9             }
10             java.util.Enumeration<String> enu = req.getHeaderNames();
11             while (enu.hasMoreElements()) {
12                 String s = enu.nextElement();
13                 log.info("header:\t" + s + " => " + req.getHeader(s));
14             }
15             log.info("response.getCharacterEncoding() => " + response.getCharacterEncoding());
16             log.info("response.getLocale().getLanguage() => " + response.getLocale().getLanguage());
17             log.info("response.getContentType() => " + response.getContentType());
18             log.info("request.getRequestURI() => " + req.getRequestURI());
19             throw (new IOException("----xxx--->>>   response is committed."));
20         }
21        
22         response.setCharacterEncoding(encoding);
23         response.setContentType("text/html; charset=utf-8");
24         chain.doFilter(request, response);
25         response.setCharacterEncoding(encoding);
26         response.setContentType("text/html; charset=utf-8");
27     }
28 

这个 Filter 在 web.xml 中,定义在 Filter Chain 中的第一个。

而出错日志则是这样的:
03 Feb 2009 18:48:20 (CharsetFilter.java:31) INFO   - response.isCommitted() => true
03 Feb 2009 18:48:20 (CharsetFilter.java:37) INFO   - cookie:   JSESSIONID => A6293E5AAC56D62B9A0AA63E6C4B4935
03 Feb 2009 18:48:20 (CharsetFilter.java:37) INFO   - cookie:   user_request_locale => zh_CN
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   user-agent => Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.43 Safari/525.19
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   referer => http://192.168.1.212:8180/mw/customerHome.action
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   accept => text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   accept-encoding => gzip,deflate,bzip2,sdch
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   cookie => JSESSIONID=A6293E5AAC56D62B9A0AA63E6C4B4935; user_request_locale=zh_CN
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   accept-language => zh-CN,zh
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   accept-charset => gb18030,*,utf-8
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   if-none-match => W/"1296-1233658401000"
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   if-modified-since => Tue, 03 Feb 2009 10:53:21 GMT
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   host =192.168.1.212:8180
03 Feb 2009 18:48:20 (CharsetFilter.java:42) INFO   - header:   connection => Keep-Alive
03 Feb 2009 18:48:20 (CharsetFilter.java:44) INFO   - response.getCharacterEncoding() => ISO-8859-1
03 Feb 2009 18:48:20 (CharsetFilter.java:45) INFO   - response.getLocale().getLanguage() => en
03 Feb 2009 18:48:20 (CharsetFilter.java:46) INFO   - response.getContentType() => null
03 Feb 2009 18:48:20 (StandardWrapperValve.java:225) WARN   - Servlet.service() for servlet default threw exception
java.io.IOException: 
        at cn.vbl.mw.web.filter.CharsetFilter.doFilter(CharsetFilter.java:
47)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:
202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:
173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:
213)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:
178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:
126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:
105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:
107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:
148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:
869)
        at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:
664)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:
527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:
80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:
684)
        at java.lang.Thread.run(Thread.java:
595)

不得其解


后记:
1. 两个地址
Bug 28331 – Unpredictable switch from UTF-8 to other encoding in Response   https://issues.apache.org/bugzilla/show_bug.cgi?id=28331
Bug 28347 – Response committed before invocation of service method      https://issues.apache.org/bugzilla/show_bug.cgi?id=28347

28347内写明了原因。

2. 解决方法
把 tomcat 的 security 加上就OK了。