Tomcat乱码问题研究,附带AJAX乱码问题研究。

Tomcat乱码问题研究,附带AJAX乱码问题研究。

很奇怪测试了多个应用服务器,只有Tomcat出现了乱码问题。让我们来分析一下原因,测试环境是Tomcat5.5.27,字符集编码统一为UTF-8

1.页面静态内容乱码(非动态生成内容乱码)
这一般是<%@ page pageEncoding="UTF-8" %>设置的问题,建议在每个页面上都加上pageEncoding设定,让应用服务器能正确把JSP文件按照设定的编码转换为Java文件,只要这个pageEncoding设置正确就可以避免静态内容的乱码。有人可能会说我没有设置也没有乱码,那是因为应用服务器还可以读取<%@ page contentType="text/html; charset=UTF-8" %>中的charset作为备选方案,虽然这是JSP规范中要求的,但是难保有的容器没有实现或实现有BUG,所以有时候在某个应用服务器下(如Tomcat)不设置pageEncoding也可以,但是同样的页面拿到别的应用服务器下就不能保证不出现乱码。

2.动态生成内容乱码
新下载的Tomcat没有经过任何特殊的设置,无论是GET和POST都出现乱码。首先设置HTTP Connector(server.xml中监听8080端口的那个Connector),加上URIEncoding="UTF-8",消除了GET乱码,再在JSP页面中第一句加入<% request.setCharacterEncoding("UTF-8"); %>,消除了POST乱码。
通过上面两个设置我们发现,URIEncoding控制的是GET字符集编码,RequestCharacterEncoding控制的是POST字符集编码。
如果没有上面那句
<% request.setCharacterEncoding("UTF-8"); %>, 在页面起始加入<%= request.getCharacterEncoding() %>,在Tomcat下我们发现输出null,在其他服务器下却输出UTF-8。这就是为什么在Tomcat下应该正确设置RequestCharacterEncoding的原因。
上面提到的<%@ page contentType="text/html; charset=UTF-8" %>,除了声明返回给客户端的流是text/html外,同时设置了ResponseCharacterEncoding,即相当于执行了Response.setCharacterEncoding("UTF-8")这段代码。它保证了服务器端生成的动态内容到达客户端也不会乱码。
但有一种情况下也不会出现乱码,就是如下例这种情况,前提是没有设置
RequestCharacterEncoding
1 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2     response.getWriter().write(request.getParameter("xxxxx"));
3 }
这种情况下提交过来的表单数据其实是ISO-8859-1的编码,而返回给客户端又没有<%@ page contentType="text/html; charset=UTF-8" %>的设置,所以还是ISO-8859-1的编码,但是为什么没有乱码呢?其实已经乱码了,如果在第2行下断点的话,会发现request.getParameter("xxxxx")的返回值就是乱码。可以用一句Java代码来解释为什么客户端显示结果没有乱码,如下:
1  System.out.println( new  String( " 你好,世界 " .getBytes( " ISO-8859-1 " ),  " ISO-8859-1 " );
很奇怪这句代码,明明是中文,应该用GB2312或GBK之类的字符集编码来getBytes,却用了ISO-8859-1,事实证明,这种互逆操作对字符串本身没有任何影响,只要getBytes和new String的时候字符集编码是一致的就不会引起乱码。
上面这句代码正好说明了数据从客户端POST到服务器端时是ISO-8859-1编码,然后从服务器端写回到客户端还是ISO-8859-1编码,所以就没有造成乱码,如果这里不是直接写回到客户端,而是forward到另一个JSP页面,而这个页面恰好使用了
<%@ page contentType="text/html; charset=UTF-8" %>来设置Response的CharacterEncoding,那么在页面中输出xxxxx还会产生乱码,同样用一句Java代码来解释,如下:
1  System.out.println( new  String( " 你好,世界 " .getBytes( " ISO-8859-1 " ),  " UTF-8 " ));
所以,最后结论是如果想POST到服务器端不乱码就要设置Request的CharacterEncoding,写回到客户端不乱码就要设置Response的CharacterEncoding,若是JSP页面要设置<%@ page contentType="text/html; charset=UTF-8" %>。

3.AJAX乱码问题(不借助任何JS框架,像Prototype之类的框架会对GET请求的queryString自动应用encodeURIComponent()编码)
GET请求时,需要对queryString使用encodeURIComponent()编码之后再提交到服务器。这是XMLHttpRequest规范所要求的。
POST请求时,不需要使用encodeURIComponent()。
通过对应用程序下断点发现,GET请求和POST请求的数据发送到服务器端都是正常的没有乱码,但是服务器端生成的动态内容写回客户端却是乱码,说明ResponseCharacterEncoding设置错误,反过来我们再想一下,我们根本就没有设置过ResponseCharacterEncoding,为什么呢?因为我们是以AJAX的方式提交表单,返回后不像JSP页面那样有<%@ page contentType="text/html; charset=UTF-8" %>来设置ResponseCharacterEncoding,所以就会出错。

综合上述,解决的办法就是各大网站提出的通用解决方案Filter,如果你的应用没有用到AJAX,只设置RequestCharacterEncoding即可,否则ResponseCharacterEncoding也要设置。下面是一个Filter的示例,只引用doFilter方法来说明问题:


1 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
2     request.setCharacterEncoding("UTF-8");
3     response.setCharacterEncoding("UTF-8");
4     chain.doFilter(request, response);
5 }


你可能感兴趣的:(Tomcat乱码问题研究,附带AJAX乱码问题研究。)