引言
GET请求的本质表现是将请求参数放在URL地址栏中,form表单的Method为GET的情况,参数会被浏览器默认编码,所以乱码处理方案是一样的。对于POST请求乱码,解决起来要比GET简单,我们关心的重点是在Request Body中。
请求乱码——Method方式
使用Method方式发送HTTP请求时,根据HTTP协议的规定,查询参数应该在Request的Body中,例如在Chrome下可以看到URL中不含有查询参数。
浏览器的编码
浏览器对POST的Request Body编码会采用页面指定的编码。这句话是我们听到最多也是众口相传的,但是到底什么是“页面指定的编码”?这个问题就涉及到我们的响应乱码问题了,用句废话就是页面显示时采用的编码,通过浏览器右键可以看到的。但是如果页面乱码了,那么页面使用的编码就是Content-Type里面指定的编码,如果Content-Type没有指定,那么就是meta标签中指定的charset,这两个编码即影响了浏览器对Page页面的解码,又影响了POST请求对Request
Body的编码。详细可以查看meta标签的http-equiv和Content-Type资料。
HTTP包传输的是字节码,不会传输字符,所以,不管是GET还是POST都需要编码。使用Chrome观察Request的Http包时,我们会发现POST的数据被放在Form Date下面,而GET的数据放在Query String Parameters页签下面。在页面没有乱码情况下,中文参数都会被默认解码。切换到View Source下面可以看到提交的编码参数。对于Request Body的长度,浏览器通过添加Content-Length报头来标记字节长度。
服务器的解码
Web容器对POST方法的解码受request.setCharacterEncoding方法的影响。对于Tomcat容器,它的官方有这样的说明:
How do I change how POST parameters areinterpreted?
POST requests should specify the encoding ofthe parameters and values they send. Since many clients fail to set an explicitencoding, the default is used (ISO-8859-1). In many cases this is not thepreferred
interpretation so one can employ a javax.servlet.Filter to setrequest encodings. Writing such a filter is trivial.
翻译过来就是:
对于POST请求,客户端应该明确的指明参数和值采用的编码类型,但是许多客户端并没有这么做,所以Tomcat会默认使用ISO-8859-1来解码POST的参数和值。许多时候,我们可以使用一个Filter来设定Request的编码,写这么个Filter是微不足道的一件小事。
简单说就是Tomcat默认使用ISO-8859-1来解码POST的参数和值,可以使用Filter来设定Request Body的字符集。方法就是调用request的setCharsetEncoding。
文档中并没有说明客户端应该如何明确说明POST请求的编码类型,但是我想可能是通过Http协议的标准报头:Accept-Charset来指定的吧。我们没必要去做这个实验,因为我们的程序绝对不应该把这件事完全托管给“不靠谱”的客户端。
所以大多数情况下,我们会在getParameter方法前调用request的setCharacterEncoding方法。就像Tomcat文档中说的,用一个自己写的或者官方提供的Filter完成这项工作就好了,Spring MVC提供的Filter也是简单的调用了这个方法:
Spring MVC 字符编码过滤器源码:
@Override protected void doFilterInternal( HttpServletRequestrequest,HttpServletResponse response,FilterChain filterChain) throws ServletException,IOException { if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding()== null)){ request.setCharacterEncoding(this.encoding); if (this.forceEncoding) { response.setCharacterEncoding(this.encoding); } } filterChain.doFilter(request, response); }
出现乱码:
POST方法出现乱码时,首先确定下我们的页面使用的是哪种编码方案,然后调用request的setCharsetEncoding,一定要在getParameter前调用这个方法。
如果仍然是乱码通过这样一个小实验就能知道哪里出错了。
(1)先获取我们的乱码,String param = req.getParameter("xx");
(2)对param = new String(param.getBytes(“服务器编码”,“页面编码”));
(3)服务器编码、页面编码要有“合理”的猜测,页面编码通过浏览器菜单观察,别相信自己写的HTML标签。服务器编码可以试验ISO-8859-1和自己set的charset encoding,然后看看哪里和自己设计的不一致,问题自然就清楚了。
总结:
POST方式的乱码比GET处理要简单,我们不用关心URL的编码,也不用编码解码URL。POST乱码,一般调用setCharsetEncoding就可以解决了。但是要注意的是,POST的数据一样是经过编码、解码的!!只不过是不用手动进行而已。
版权声明:本文为博主原创文章,未经博主允许不得转载。