一、乱码的原因
乱码:当编码与解码不一致时,就会出现乱码的情况。(本质:编解码不一致)
根据乱码又可分为:
(1)请求乱码:客户端编码与服务器解码不一致
(2)响应乱码:服务器编码与客户端解码不一致
编码:将字符转换为二进制的过程称之为编码
解码:将二进制转换为字符的过程称之为解码
二、默认的编解码
1、服务器端(Tomcat)的编解码
Tomcat 默认是使用 ISO8859-1来编解码的。(ISO8859-1是不支持中文的)
注意:① Tomcat8(包含8)以上版本默认编码格式是 UTF-8
② HttpServletRequest 和 HttpServletResponse容器默认编码格式是 ISO-8859-1
2、客户端的编解码
浏览器的编码:默认是 GB2312。
影响form提交数据的编码的因素包括:form的accept-charset属性、html文档的编码方案即document.charset。其中,form的accept-charset是否能够有效,依赖具体浏览器的实现,有些浏览器并不支持,如IE。文档编码方案可以通过document.charset来修改。(<meta charset="UTF-8">)
浏览器的解码:默认是GBK/GB2312。
通常来说,浏览器会先按照Content-Type的编码设置来解析文本,然后在解析过程中发现charset设置,再更换编码重新读取。若Content-Type没有设置编码,或者说这个HTML文件根本就不是走的HTTP协议,浏览器通常会猜测编码来解析文本,然后发现charset设置再更换编码读取。
3、Get 和 Post 解码格式
request 容器保存的是浏览器的数据,一般是 UTF-8 格式。
request的方法如:getParameter解码格式会根据Get和Post来设置解码格式。因为Get和Post的取值放在不同地方。所以要分开考虑。
1. Get是 URL 解码方式。默认解码格式是 Tomcat8 编码格式。所以URL解码是 UTF-8,覆盖掉了 request 容器解码格式
2. Post 是实体内容解码方式。默认解码格式是request编码格式。与Tomcat8编码格式无关
三、GET 请求乱码解决
虽然 Response容器默认以 ISO-8859-1 的编码解析数据
但是对于get请求提交的数据,在不同版本的 Tomcat中有不同的处理方式,在 Tomcat8 及以上的版本,服务器默认以 UTF-8 的编码方式处理请求参数
1、方案一:Tomcat 版本8以上不用指定编码格式,默认 utf-8
而对于 Tomcat8 以下的版本,服务器会默认以ISO-8859-1的编码方式处理请求参数
2、方案二:编码二次转换(推荐)
注意:
utf-8-》iso-8859-1》utf-8 原样
utf-8-》GBK-》utf-8 乱码
具体参考这篇:编码转换问题
现在基本都是Tomcat8以上版本 ,所以不存在编码问题,而如果是Tomcat8以下版本解决方案:
// 获取请求参数
String username = req.getParameter("username");
//1 先以 iso8859-1 进行编码
//2 再以 utf-8 进行解码,手动解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
3、方案三:
设置指定解码 URL 的编码格式:URIEncoding="UTF-8" (不推荐,依赖服务器,有时候没法设置服务器)
对于 get 请求需要在修改 Tomcat 服务器里面的server.xml文件的配置:(或者Tomcat目录下的/conf中的 server.xml进行设置)
注意:tomcat8.0以后get请求默认使用UTF-8进行解码,所以此配置只针对tomcat8.0以前的版本
<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
4、方案四
请求参数的编码方式要采用请求体的编码方式(不推荐依赖服务器,有时无法设置服务器)
useBodyEncodingForURI=true是说,。当useBodyEncodingForURI=true时,若请求体采用 utf-8 解析,则请求参数也要采用 utf-8 来解析。
server.xml:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" useBodyEncodingForURI="true" />
Servlet:
doGet(){
request.setCharacterEncoding("utf-8");
}
分析:
① request.setCharacterEncoding("utf-8");只是作用于实体内部,意思就是说对Post有效,对Get无效。
② 但是设置useBodyEncodingForURI="true"后URL解码格式和实体内容解码格式一样。
注意:如果只是设置useBodyEncodingForURI="true那get URL解码格式就是默认iso-8859-1,因为实体内部默认是这个解码格式,即使Tomcat版本8以上默认编码格式为UTF-8也会被iso-8859-1覆盖掉。
四、POST 请求乱码解决
Tomcat服务器中 Request 容器默认以 ISO-8859-1 的编码解析数据,因此如果需要在参数中解析中文,需要设置对于 post 请求的乱码,可以设置 request 对象的编码格式为 UTF-8即可。
request.setCharacterEncoding("UTF-8");
注意:
① 要写在获取参数前面,不然无法生效;
② 设置参数查询的编码;
③ 该方法只能对Response容器的请求实体内容的数据编码起作用。POST提交的数据在实体内容中,所以该方法对POST方法有效!
④ GET 方法的参数放在 URI 后面,所以对 GET 方式无效;
扩展:也可以为整个 JavaWeb 项目配置字符过滤器。
1 <filter>
2 <description>字符集过滤器</description>
3 <filter-name>encodingFilter</filter-name>
4 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
5 <init-param>
6 <description>字符集编码</description>
7 <param-name>encoding</param-name>
8 <param-value>UTF-8</param-value>
9 </init-param>
10 </filter>
11 <filter-mapping>
12 <filter-name>encodingFilter</filter-name>
13 <url-pattern>/*</url-pattern>
14 </filter-mapping>
五、响应乱码解决
响应乱码解决方案:给服务器和浏览器设置统一的编解码。
方案一:(不推荐使用)
1 // 设置服务器字符集为 UTF-8
2 response.setCharacterEncoding("UTF-8");
3
4 // 通过响应头, 设置浏览器也使用 UTF-8 字符集
5 response.setHeader("Content-Type", "text/html; charset=UTF-8");
方案二:(推荐使用)
1 // 它会同时设置服务器和客户端都使用 UTF-8 字符集, 还设置了响应头
2 // 此方法一定要在获取流对象之前调用才有效
3 response.setContentType("text/html; charset=UTF-8");
六、总结
1、中文建议使用post而不是get
2、Tomcat8版本以上默认是UTF-8对GET方法来说,对POST无效,因为request.getParameter默认调用·iso-8859-1·
3、get方式参数存放在请求数据包的请求行的URI字段中,以?开始以param=value¶me2=value2的形式附加在URI字段之后,而Post是放在实体内部。
4、request.setCharacterEncoding(charset);只对消息体中的数据起作用,对于URI字段中的参数不起作用。默认作用于POST,对GET无效。
当使用request.setCharacterEncoding(charset);时,只能解决表单方法为POST的中文乱码情况,而方法为GET的依然为乱码。
5、request.setCharacterEncoding(“UTF-8”) 解决 post 乱码
6、useBodyEncodingForURI=”true”目的是URL解码格式和实体内部解码格式相同。
7、如果使用JS编程时,在浏览器可以使用encodeURIComponent函数对中文参数进行编码后再拼装参数。