ajax post请求中文乱码问题解决(不使用escape方法,只使用filter)

来源:互联网 发布:网络主播歌曲大全 编辑:程序博客网 时间:2024/04/29 16:30
本人另一篇博客总结了三种方案的比较,并提出了一种比本方案更好的一个方案,请参考:http://hjg1988.iteye.com/blog/472080 

    相信很多人都遇到过乱码问题,尤其在使用了一些web框架之后。但是大部分情况下,都是可以通过框架本身提供的配置来设置字符集编码来解决。比如,在webwork中,我们可以通过在webwork.properties中使用这种方法来设置字符编码: 

webwork.i18n.encoding=GBK
这时候,只需要使所有页面的charset="GBK"(与webwork的配置保持一致)即可避免大部分乱码问题。但是,如果我们希望使用Ajax的post请求(使用XmlHttpRequest对象而非隐藏的frame),那么,post的参数在后台中取出的时候依然是乱码(本人在IE和Firefox下测试过)。而如果使用隐藏的frame来做Ajax请求,那么将不会出现这种问题。 
    出现这种情况的原因是由于,W3C标准中规定,XmlHttpRequest对象的post请求的编码只能是UTF-8的,这样除非我们将webwork的配置设置为 

webwork.i18n.encoding=UTF-8
webwork.i18n.encoding=UTF-8否则Ajax的post请求编码将不能与框架的编码设置一致,从而导致乱码。当然如果我们所有的页面都使用UTF-8编码,那将不会有问题,但有的时候我们可能希望页面编码是GBK或GB2312的,这时候如果将配置设为UTF-8会导致普通页面乱码。 
    Web框架对与编码设置仅仅是保证了在第一次调用request.getParameter()(或getParameterMap()等)之前调用request.setCharacterEncoding()方法来设置编码——即使不使用框架,我们也会这么做。于是有人可能会认为,那只要在发送Ajax post请求时,在请求参数中增加一个参数用来说明这是一个Ajax post请求,这样后台只要先getParameter()取出这个参数作为判断,就然后再调用request.setCharacterEncoding()来设置相应的编码——但这当然不会有效果,因为一旦已经调用过了getParameter()方法,setCharacterEncoding()方法就已经失效了,它必须在所有取得参数的方法之前调用。 
    这种方式虽然不能解决问题,但是思路却是很好的。既然不能通过getParameter()方法来判断是否是一个特殊的请求,但是我们可以在请求的url中加入一个参数名称(可以不需要值),然后在后台通过使用request.getQueryString()方法,取得所有请求参数,然后判断是否存在这个参数名称,即可知道是否需要设置编码。当然,这些操作我们必须写在一个servlet的filter里面,并保证这个filter在所有其它filter和web框架的servlet或filter之前被调用即可。下面是笔者写的一个例子(这是我自己的解决方案,说不定大家还有其它更好的方式可以解决,希望指点)。 
    当然,有很多人都已经有另一种解决方案了,那就是在前端发送数据之前使用escape函数对要发送的数据进行编码,后台取出后再进行解码就可以获得正确的中文,但是笔者不推荐使用这种方式。这样虽然可以解决问题,但是前端和后台的藕合度比较大——一方面前端需要做工作比较多,需要加入一些与普通操作无关的代码,另一方面需要在后台具体的业务逻辑代码中加入解码的代码,而这些代码实际上与业务逻辑无关,这样的藕合不是很必要。而下面的方法,只需要前端的请求url加入一个可配置(web.xml中配置)的参数名称(类似与一个命令)即可,这种方式有点像命令模式,对解藕有帮助。 

package com.hjg.demo;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;/** * 如果request中含有__ajax__参数,则对其参数的进行编码 *  * @author jinggang.huangjg *  */public class RequestEncodingFilter implements Filter {/** ajax请求的编码 */public final String ajaxEncoding = "utf-8";private boolean ignore = false;/** url请求参数中用户标志是否是一个ajax请求的标志名称 */private String ajaxFlag = "__ajax__";public void destroy() {}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {if(ignore){chain.doFilter(request, response);return;}HttpServletRequest req = (HttpServletRequest) request;// 这里不使用getParameter方法,否则会使后续setCharacterEncoding方法失效String queryString = req.getQueryString();// 如果请求url参数中含有flag(默认为__ajax__),则表明使用ajax请求,则编码设置为utf-8if (queryString != null && queryString.indexOf(ajaxFlag) != -1) {request.setCharacterEncoding(ajaxEncoding);// 调用一次getParameter方法,使得在此之后再调用setCharacterEncoding将会无效// (web框架会在之后再调用此方法,但是已经失效)// 参数不一定为ajaxFlag,可以是任何值request.getParameter(ajaxFlag);}chain.doFilter(request, response);}public void init(FilterConfig filterConfig) throws ServletException {String value = filterConfig.getInitParameter("ignore");ajaxFlag = filterConfig.getInitParameter("ajaxFlag");if(ajaxFlag == null){ajaxFlag = "__ajax__";}if (value == null){ignore = false;}else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")){ignore = true;}else{ignore = false;}}}

然后我们在web.xml中配置:

<filter><filter-name>request-encoding</filter-name><filter-class>com.hjg.demo.RequestEncodingFilter</filter-class><init-param><!-- 这个如果不配置,则默认为__ajax__ --><param-name>ajaxFlag</param-name><param-value>__ajax__</param-value></init-param></filter>...<filter-mapping><filter-name>request-encoding</filter-name><url-pattern>*.action</url-pattern></filter-mapping>

这样,当我们要使用Ajax来post数据时,我们可以使用类似下面这样的请求URL: 

demo.action?__ajax__&param=value...

而对于普通的数据提交不需要任何改动,因为普通的表单提交所使用的编码是与页面编码保持一致的。这样Ajax post的乱码问题就可以解决了。

0 0
原创粉丝点击