Servlet 中文乱码解决方案(Web容器:Tomcat7)

一,产生原因

首先,我们需要了解的是,在计算机磁盘存放的是字节,在网络中传输的也是字节。将字节转换为我们可识别的字符的过程就叫做编码,相反将字符转换成字节的过程就称之为解码。解码和编码都需要指定具体的编码方式,不同的字符集规定了不同字符存储方式,比如 GBK 编码中的中文文字占2个字节,而 UTF-8 编码中的中文字符通常占3个字节。之所以产生乱码,是因为我们对同一个字符的编码和解码使用了不同的字符集导致的。打个比方,假如我们将“中国”两个字符用 UTF-8 进行编码,则将产生六个字节,再将这六个字节使用 GBK 进行解码,将产生三个字符,这就是我们通常我们所说的乱码现象。还有一种情况也会产生乱码,就是我们在对源字符串进行解码时使用了错误的编码方式,比如 ISO-8859-1 编码方式的字符集不支持中文,如果使用这个编码方式对中文进行解码,再编码后得到的结果必然是乱码无论。

二,Servlvet 中请求参数包含中文,产生乱码解决方案和原理分析

1,原理分析

当我们使用 Request 对象获取请求参数时,其底层是通过读取网路中的输入流来实现的。在 Java 中无论是通过字节流还是通过字符流来读取输入流中的内容,都是通过 InputStream 这个类来实现的,而 InputStream 读取的字节的编码方式是由文件本身的编码决定的。如果使用 Tomcat 版本小于8,则 Servlet 再读取请求参数默认使用的编码方式为 ISO-8859-1(为什么默认为 ISO-8859-1 ,请参考这篇 Wiki ),而请求参数真正使用的编码方式是由创建请求的执行者决定的,这就导致了编码和解码使用了不同的编码方式。

2,解决方案

1)先将字符串进行解码,然后使用正确的编码进行编码

	Enumeration<String> parameterNames = req.getParameterNames();
	while (parameterNames.hasMoreElements()) {
	        String parameterName = parameterNames.nextElement();
	        String parameterValue = req.getParameter(parameterName);
	        // 先用"ISO-8859-1"对参数进行解码,然后使用"UTF-8"重新编码
	        parameterValue = new String(parameterValue.getBytes("ISO-8859-1"), "UTF-8");
	        System.out.println(parameterName + "=" + parameterValue);
	}

2)修改默认的编码方式
对于 POST 请求,在获取请求参数前调用 Request 对象的 setCharacterEncoding 方法,来修改解析请求体的默认编码

req.setCharacterEncoding("UTF-8");

对于 GET 请求,因为 GET 请求是直接拼接在 URL 中的,所以调用上面的方法将不会起作用。我们需要修改服务器的配置,来修改 GET 请求默认使用的编码方式,即需要修改 Tomcat 配置(conf)目录下的 server.xml 配置文件。

a.在 元素中添加 URIEncoding 属性来直接指定默认的编码方式


 <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

 <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" 
               URIEncoding="UTF-8" />

b.在 元素中添加 useBodyEncodingForURI 属性,来指定使用请求体的编码方式来解析 GET 请求参数,即设置了这个属性以后,我们是使用 setCharacterEncoding 方法,同样也会影响 GET 请求


 <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

 <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" 
               useBodyEncodingForURI="true" />

三,Servlvet 响应中包含中文,产生乱码解决方案和原理分析

1,原理分析

客户端(浏览器)再解析我们传递过去的字符串时,使用了不同的编码方式。

2,解决方案

在响应时使用统一的编码方式(最好使用 UTF-8,节省空间),然后告知客户端我们使用的编码方式。
a.第一种方式

// 告知客户端使用的编码方式为"UTF-8"
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
// 设置编码方式为"UTF-8"
resp.setCharacterEncoding("UTF-8");
// 如果不设置上面的编码方式,则这里的 PrintWriter 默认使用"ISO-8859-1"
resp.getWriter().write("你好");

b.第二种方式

// 告知客户端使用的编码方式为"UTF-8"
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
// 直接使用"UTF-8"进行解码
resp.getOutputStream().write("你好".getBytes("UTF-8"));

c.第三种方式

// 设置编码方式为"UTF-8",并告知客户端使用的编码方式为"UTF-8"
// 需要再响应前调用
resp.setContentType("text/html;charset=UTF-8");
// 响应的两种方式
resp.getWriter().write("你好");
// or
// resp.getOutputStream().write("你好".getBytes("UTF-8"));

四,参考链接

1,java中的编码问题
2,Tomcat Wiki FAQ/CharacterEncoding

你可能感兴趣的:(Java,Servlet,HTML,JavaEE,Web,学习笔记)