同事在Get请求时,参数带有中文,在Tomcat服务器上接收到的是乱码,所以特意研究了一下,主要是因为Tomcat在解析字符的时候使用的编码与浏览器使用的不一致导致的。
原因
在Tomcat中,所有字符默认是按ISO-8859-1的编码格式来编码的,这是欧洲使用的一种字符编码格式。在浏览器发起http请求时,将请求的url以及参数按服务器指定的UTF-8编码后发送到Tomcat,这时Tomcat并不知道发送来的字符是按什么编码的,使用默认的ISO-8859-1格式来解析字符,导致中文乱码。
解决
POST请求
http的post请求参数是在请求体中,不直接暴露到url中,在javaee中request中有一个设置编码的方法
void setCharacterEncoding(java.lang.String env);
该方法需在所有getParameter方法调用之前调用,设置好UTF-8格式后,再通过getParameter方法获取带中文的参数,可以正常显示。如果使用Spring框架,在注解的方法中使用该方法无效,个人认为是在该方法前框架内已经调用getParameter,导致之后设置无效。解决方法是在web.xml文件中,在spring-servlet前配置拦截器,过滤所有请求,将使编码设为UTF-8,中文可正常显示。
可使用spring框架中的org.springframework.web.filter.CharacterEncodingFilter来设置请求体的编码格式
GET请求
http的get请求参数是直接拼接到url后边的,通过?name=val&name1=val1的形式发送到后台服务器,通过测试发现,设置编码拦截器后,post请求体的中文可正常显示,get的参数不能正常显示。
方法1
不修改任何配置,在代码中转码,这种方法可行,不过得在所有可能出现中文的地方转码,比较费事,也不推荐,具体代码。
String para_utf8=new String(para.getByte("ISO-8859-1"),"UTF-8");
方法2
修改Tomcat配置,打开Tomcat帮助文档,路径为Reference->Configuration->HTTP中,在Connector节点中有如下两个属性。
URIEncoding
This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
useBodyEncodingForURI
This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitly set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.
Notes: 1) This setting is applied only to the query string of a request. Unlike URIEncoding it does not affect the path portion of a request URI. 2) If request character encoding is not known (is not provided by a browser and is not set by SetCharacterEncodingFilter or a similar filter using Request.setCharacterEncoding method), the default encoding is always "ISO-8859-1". The URIEncoding setting has no effect on this default.
URIEncoding是请求的url中字符的编码,会将url中%xx这样的url按这里指定的编码格式去解码,如果不指定则会使用默认的 ISO-8859-1 。
我是在Connector节点中添加的第二个属性useBodyEncodingForURI="true",该属性是使用body体的编码格式去解析url中的%xx。