response与request中文乱码问题及解决方式

前言:在Javaweb开发过程中可能会遇到乱码的问题,本文整理了几个常用的乱码解决方式

一.编码基础知识

1.四种常见编码

ISO-8859-1 单字节编码,兼容ASCII码,相当于ASCII码的扩展,无法表示中文字符,系统默认编码
GBK 双字节编码,国标码,可以表示繁体字和简体字,而GB2312编码只能表示简体字,GBK兼容GB2312编码
UNICODE 定长双字节编码,可以表示所有语言的字符,不兼容任何编码,很多软件内部是使用unicode编码来处理的
UTF 不定长编码,可以表示所有语言的字符,常用UTF-8,兼容iso8859-1编码,UTF编码会比UNICODE编码节省

2.java对字符编码的处理

getBytes(charset)
这是java字符串处理的一个标准函数,其作用是将字符串所表示的字符按照charset进行编码,并以字节方式表示。
new String(charset)
这是java字符串处理的一个标准函数,其作用是将字节数组按照charset编码进行组合识别,最后转换为unicode存储。
setCharacterEncoding()
该函数用来设置http请求或者相应的编码。

3.编码规律总结

通常情况下,我们认为可以把得到的以 GBK 编码的乱码数据,解码后再编码成UTF-8正确显示;可以把得到的以 ISO-8859-1 编码的乱码数据,解码后再编码成GBK正确显示。但是,本人经过多次验证发现,并不是每次都能成功的处理乱码问题,本人认为可能是如下原因(仅代表个人观点,欢迎批评指正):例如使用ISO-8859-1 编码的中文数据,由于ISO-8859-1 的码表里没有中文对应的二进制代码,所以使用ISO-8859-1 编码得到的二进制代码不符合ISO-8859-1 编码规范,同样也不符合其他任意码表的编码规范(谁知道电脑是怎么表示中文的?反正我不知道!管他呢!)。所以即使我们把乱码的中文还原成字节码,也不能使用任何码表成功解析字节码了,因为还原后的字节码不符合任意码表的编码规范。所以,最好的解决办法就是从源头上解决问题,例如编码时必须使用UTF编码,只有这样,我们后期才能更好的处理数据。

二.request和response的中文乱码问题

1.乱码产生的原因

无论数据是在传输还是存储等过程中,都是以字节的方式在运行,但是数据内容是经过编码后再进行传输的。
由于浏览器跟服务器端在编码和解码时采用了不同的码表,所以会产生乱码。

2.两个乱码类型

response乱码:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码
request乱码:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码

三.乱码解决方案

1.response乱码

服务器发给浏览器的数据默认是按照ISO-8859-1编码(可以通过设置修改服务器编码方式),浏览器接收到数据后按照当前页面的显示编码进行解码后显示,如果浏览器的当前页面编码不是服务器的编码,就出现乱码。例如如果服务器使用ISO-8859-1编码中文字符,浏览器接受到的数据一定是乱码,因为ISO-8859-1不包括中文字符。
对于response乱码,只需要在服务器端指定一个编码方式,然后通知浏览器按照这个编码方式进行解码就可以了。

关于字符流的问题

response.setCharacterEncoding("UTF-8");
//设置服务器端的编码,默认是ISO-8859-1;该方法必须在response.getWriter()之前进行设置才会生效
response.setHeader("content-type", "text/html; charset=utf-8");
//通知浏览器服务器发送的数据格式是text/html,并要求浏览器使用utf-8进行解码。
response.setContentType("text/html;charset=utf-8");
//通知浏览器服务器发送的数据格式是text/html,设置服务器采用utf-8编码,并要求浏览器使用utf-8进行解码。相当于上面两句代码的封装,一句话完成两句话的功能
response.getWriter().println("<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>");
 //要求浏览器使用utf-8进行解码,相当于第二句代码要求浏览器解码方式的底层代码

关于字节流问题

//服务端对字符进行编码的时候,指定编码方式
response.getOutputStream().write("汉字".getBytes("UTF-8"));
//同时设置浏览器的解码方式
response.setHeader("content-type", "text/html;charset=UTF-8");
response.setContentType("text/html;charset=UTF-8");

其中字符响应流只能用来输出字符,而字节响应流可以用来输出任何东西。

2.request乱码

浏览器发送时文字编码时编码方式是和页面显示编码保持一致的。
从浏览器发起的访问方式有三种:在地址栏直接输入URL访问、点击超链接访问、提交表单访问。
在地址栏直接输入URL访问时(GET请求),浏览器默认将参数按照UTF-8进行编码
点击超链接访问和提交表单访问时浏览器将参数按照当前页面的显示编码进行编码
在服务器端,通过request.setCharacterEncoding("UTF-8")即可设置服务器的解码为UTF-8
但是它只对请求体(post请求)里面的参数有效,如果参数跟在请求行中的URI后边(GET请求),它就无能为力了。
因此请求方式不同,解决乱码的方案也不同。

A.表单访问post请求乱码

post方式提交的参数存在于请求体中,浏览器将参数按照当前页面的显示编码进行编码
页面的编码方式一般情况下已经被设置成了UTF-8,只需要修改服务端解码方式(与浏览器页面编码方式一致)
request.setCharacterEncoding(“UTF-8”);

B.表单访问get请求乱码与超链接访问乱码

get方式提交的参数会跟在请求行中的URI后边,浏览器将参数按照当前页面的显示编码进行编码
get请求乱码办法一:修改服务器端对URI参数的默认编码
在tomcat的server.xml中,设置元素的属性URIEncoding=”UTF-8”即可。(默认没有设置此属性)
扩展:
1.设置元素的属性useBodyEncodingForURI=“true”,意思是请求体和uri使用相同的编码格式。
通过设置这两个属性,既可以解决get方式的乱码,又可以解决post方式的乱码。
2.通过修改server.xml指定服务器对get和post统一按照utf-8解码,要求tomcat管理下的所有web应用都要使用utf-8编码,即所有的jsp、html页面都必须使用utf-8编码。

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

get请求乱码办法二:逆向操作
参数从浏览器到服务器,经过客户端编码,服务器端解码,最终成为乱码。那我们将乱码进行相反的编解码,即可得到正常的参数值。此时注意上文提到的编码规律总结,只有源头对了,才能成功解决问题。

String name = request.getParameter("name");//得到乱码的数据    
name = new String(name.getBytes("GBK"),"utf-8");
//将得到的数据进行GBK方式解码,然后把得到的字节再通过UTF-8编码,得到正常的name值     

注意:name.getBytes();如果不指定编码,默认按照gb2312进行编码。
get请求乱码方法三.手动编码解码
在JSP页面中先把中文编码后再提交,服务器获取后再按照同样的方式解码
主要利用URLEncoder类,仅供了解不做研究。

四.扩展

html文件编码要和保存的编码类型相同
编码声明要放在最前面,比如要放在标题之前
中文页面编码用gbk或gb2312或UTF-8等
<meta charset="UTF-8">就是声明字符集使用的UTF-8

猜你喜欢

转载自blog.csdn.net/bestmy/article/details/81048427