引言
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报头来标记字节长度。
server的解码
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请求,client应该明白的指明參数和值採用的编码类型。可是很多client并没有这么做。所以Tomcat会默认使用ISO-8859-1来解码POST的參数和值。
很多时候,我们能够使用一个Filter来设定Request的编码,写这么个Filter是微不足道的一件小事。
简单说就是Tomcat默认使用ISO-8859-1来解码POST的參数和值,能够使用Filter来设定Request Body的字符集。方法就是调用request的setCharsetEncoding。
文档中并没有说明client应该怎样明白说明POST请求的编码类型,可是我想可能是通过Http协议的标准报头:Accept-Charset来指定的吧。我们不是必需去做这个实验。由于我们的程序绝对不应该把这件事全然托管给“不靠谱”的client。
所以大多数情况下,我们会在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(“server编码”,“页面编码”))。
(3)server编码、页面编码要有“合理”的推測。页面编码通过浏览器菜单观察。别相信自己写的HTML标签。server编码能够试验ISO-8859-1和自己set的charset encoding。然后看看哪里和自己设计的不一致,问题自然就清楚了。
总结:
POST方式的乱码比GET处理要简单。我们不用关心URL的编码,也不用编码解码URL。
POST乱码。一般调用setCharsetEncoding就能够攻克了。可是要注意的是,POST的数据一样是经过编码、解码的。!仅仅只是是不用手动进行而已。