编码问题总是为难我小小程序员
文章目录
1 response 输出乱码问题
response 有两个输出方法,即 getOutputStream()
和 getWriter()
1.1 调用getOutputStream()方法向浏览器输出数据
当调用 getOutputStream()
方法向浏览器输出数据时,该方法可以使用 print()
(ServletOutputStream的方法,输出字符串)或 write()
(OutputStream的方法,输出 byte[]) 执行输出,下面分别看看它们的使用方法和区别(也可以查看源码看看两种方法的实现):
1)
print()
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String s1 = "IO Stream";
//获取response的OutputStream流
ServletOutputStream out = response.getOutputStream();
//输出结果显示到浏览器
out.print(s1);
}
浏览器输出结果:
成功输出,貌似没什么问题!但试着输出中文:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String s1 = "字节输出流";
ServletOutputStream out = response.getOutputStream();
out.print(s1);
}
结果却是报了异常:
报异常的原因:OutputStream 输出二进制数据,print() 方法接收了一个中文字符串,且 print() 要将中文字符串改为二进制数据输出,而 Tomcat 使用 ISO 8859-1编码使其进行转换,ISO 8859-1 自身是不能显示中文的。
2)
write()
英文字符是都能正常输出的,下面就直接试试中文字符:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String s1 = "字节输出流";
ServletOutputStream out = response.getOutputStream();
out.write(s1.getBytes());
}
浏览器输出结果:
正确输出了。这是因为 s1.getBytes()
将字符串转化为 byte[] 数组后默认的编码方式是 GB 2312 ;而 GB 2312 支持简体中文的输出(print 输出内容只能是字符串,不能转化为 byte[])。
但是,程序要实现通用性,就需要使用 UTF-8 编码,若是在字节数组中指定使用 UTF-8 编码,则会出现乱码:
out.write(s1.getBytes("utf-8"));
乱码的原因是因为服务器指定使用 UTF-8 编码,但浏览器显示往往不是采用 UTF-8 编码(如 GBK,GB2312等等),这样就导致乱码!
解决:http 响应消息有对浏览器说明响应数据是什么类型的响应头字段,即为 Content-Type,通过设置 Content-Type 的值即可解决。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置浏览器使用 utf-8 编码显示数据
response.setHeader("Content-Type", "text/html;charset=UTF-8");
//等效
//response.setContentType("text/html;charset=UTF-8");
String s1 = "字节输出流";
ServletOutputStream out = response.getOutputStream();
out.write(s1.getBytes("utf-8"));
}
1.2 调用getWriter()方法向浏览器输出数据
PrintWriter 是 Writer 的子类,只能向浏览器输出字符数据,而不能输出二进制数据。getWriter() 是response 获取 PrintWriter 对象的方法,同样,它也可以通过 print()
或 write()
输出数据到浏览器显示。
PrintWriter 中的 print() 和 write()【多看看源码】
PrintWriter 中的 print() 方法的实现都是调用 write() 方法,但是 print() 提供了更多的参数类型,write() 输出字符串,如:
//诸如此类
public void print(Object obj) {
write(String.valueOf(obj));
}
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
那么,就说说 write() 输出时的编码问题:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String s2 = "字符输出流";
PrintWriter out = response.getWriter();
out.write(s2);
}
又是乱码!!!!
原因:Tomcat 对浏览器进行响应时默认采用 IOS 8859-1 编码,而这个编码方式不支持中文。response.setCharacterEncoding("UTF-8")
可以设置 Tomcat 的编码为 UTF-8(但需要注意浏览器的显示编码方式,往往浏览器显示的编码方式不是 UTF-8 又容易产生乱码)。
那么就需要进行设置编码。设置编码的方式有很多:设置 Content-Type 头字段的值,或者输出标签模拟消息头等等。最简单的可以只通过一个方法 setContentType
就ok。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置编码(它不仅设置浏览器用UTF-8显示数据,内部还把中文转码的码表设置成UTF-8了)
response.setContentType("text/html;charset=UTF-8");
String s2 = "字符输出流";
PrintWriter out = response.getWriter();
out.write(s2);
}
2 request 获取数据乱码问题
request 对于 POST 和 GET 两种方式的请求处理中文乱码的方式有所不同。
2.1 POST 中文乱码解决
表单:
//前端显示/提交数据编码
<meta charset="UTF-8">
....
//post方法提交表单数据
<form action="Test01Servlet" method="post">
姓名: <input type="text" name="name"><br>
简介:<input type="text" name="intro">
<input type="submit" />
</form>
提交数据:
后台获取数据:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置服务端接收数据编码(重点)
request.setCharacterEncoding("utf-8");
String name = request.getParameter("name");
String intro = request.getParameter("intro");
System.out.println(name);
System.out.println(intro);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
获取数据:
带 request.setCharacterEncoding("utf-8")
语句可解决 post 方式提交表单出现的中文乱码。若没有该语句,控制台打印结果:
这是因为 Tomcat 默认编码为 ISO-8859-1,浏览器页面使用的 UTF-8(<meta charset="UTF-8">
);这样的话,Servlet 读取数据时自然就得到乱码,在 post 提交方式下,简单通过 request.setCharacterEncoding("utf-8")
设置编码即可解决。
2.1 GET 中文乱码解决
不仅表单指定的 GET 方式,超链接默认也是 GET 提交方式。
先看看 GET 提交数据的方式与 POST 有何不同!
POST提交数据:点击提交时,数据封装进了 From Data 中,然后 http 请求将消息主体发送给服务端,此时 request 对象封装有 http 请求,自然就可以解析 http 中的 From Data 数据,这时只要把request 编码设置为 UTF-8 即可
GET提交数据:GET 的数据时通过消息行带给服务端的,而没有封装到 request 对象中,此时,即使设置 request 编码也不起作用
那么,GET 方式出现的中文乱码又怎么解决???
方法一:将 GET 的数据反向查 ISO 8859-1 编码(既然它是因为 ISO 8859-1 而乱码,就先找到它的未经编码的原始数据)
//获取数据(经ISO 8859-1编码后的字符串,乱码)
String name = request.getParameter("name");
String intro = request.getParameter("intro");
//乱码通过反向查ISO 8859-1得到原始的数据
byte[] bytename = name.getBytes("ISO8859-1");
byte[] byteintro = intro.getBytes("ISO8859-1");
//对原始的数据,设置编码,构建字符串
String name_1 = new String(bytename,"UTF-8");
String intro_1 = new String(byteintro,"UTF-8");
System.out.println(name_1 );
System.out.println(intro_1 );
方法二:除了上面的手工转换,还可以通过修改 Tomcat 服务器的配置解决服务器在解析数据时造成的中文乱码
<!-- URIEncoding="utf-8"的增加使得get方法编码问题得到纠正 -->
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8888" protocol="HTTP/1.1" redirectPort="8443"/>
这种改法是固定使用 UTF-8 编码的(过于依赖服务器)
一般来说,能使用 POST 方式提交数据的就用 POST。