三、JavaWeb中出现的⼀些乱码问题总结(详解)
⼀、Writer().write()和 Writer().print()的区别
1. print
2. writer
⼆、常见乱码问题分析
1、中⽂变成看不懂的字符
如果⼀串中⽂字符变成了⼀串看不懂的字符如:“ÌÔ£¡ÎÒϲ»¶£¡”,这种情况通常是编码
字符集与解码时所⽤的字符集不⼀致所造成的。⽐如使⽤GBK编码,如果使⽤ISO-8859-1解码
的话结果就是这样。
2、⼀个汉字变成了⼀个问号
如果编码和解码的字符集都是⼀致的,那么可以确定该字符编码不⽀持中⽂,例如:ISO-8859-1
3、⼀个汉字变成了两个问号
中⽂经过多次编码且其中有⼀次编码或者解码使⽤了不⽀持中⽂的字符集
三、乱码相关知识点:
1.UTF-8国际编码,GBK中⽂编码。GBK包含GB2312,即如果通过GB2312编码后可以通过GBK解码,反之可能不成⽴;
2、web tomcat:默认是ISO8859-1,不⽀持中⽂的
3.java.nio.charset.Charset.defaultCharset() 获得平台默认字符编码;
5.码表:是⼀种规则,⽤来让我们看得懂的语⾔转换为电脑能够认识的语⾔的⼀种规则,有很多中码表,IS0-8859-1,GBK,UTF-8,UTF-16等⼀系列码表,⽐如GBK,UTF-8,UTF-16都可以标识⼀个汉字,⽽如果要标识英⽂,就可以⽤IS0-8859-1等别的码表。
6.编码:将我们看得懂的语⾔转换为电脑能够认识的语⾔。这个过程就是编码的作⽤
7.解码:将电脑认识的语⾔转换为我们能看得懂得语⾔。这个过程就是解码的作⽤
浏览器使⽤的是UTF-8码表,通过http协议传输,http协议只⽀持IS0-8859-1,到了服务器,默认也是使⽤的是IS0-8859-1的码表,看图
也就是三个过程,经历了两次编码,所以就需要进⾏两次解码,
1、浏览器将"⼩明"使⽤UTF-8码表进⾏编码(因为⼩明这个是汉字,所以使⽤能标识中⽂的码表,这也是我们可以在浏览器上可以⼿动设置的,如果使⽤了不能标识中⽂的码表,那么就将会出现乱码,因为码表中不到中⽂对应的计算机符号,就可能会⽤??等其他符号表⽰),编码后得到的为 1234 ,将其通过http协议传输。
2、在http协议传输,只能⽤ISO-8859-1码表中所代表的符号,所以会将我们原先的1234再次进⾏⼀次编码,这次使⽤的是ISO-8859-1,得到的为 ,然后传输到服务器
3、服务器获取到该数据是使⽤UTF-8编码的,⽽tomcat服务器默认使⽤ISO-8859-1解码,由于编码和解码所使⽤的字符集不⼀致,所以会出现乱码问题。
解决⽅案: 如果我们在客户端使⽤UTF-8编码的JSP页⾯发出请求,浏览器编码后的UTF-8字节会以ISO-8859-1的形式传递到服务器端。所以要得到经HTTP协议传输的原始字节,我们需要先调⽤getBytes(“ISO-8859-1”)得到原始的字节,但由于我们客户端的原始编码是UTF-8,如果继续按照ISO-8859-1解码,那么得到的将不是⼀个中⽂字符,⽽是3个乱码的字符。所以我们需要再次调⽤new
String(bytes,“UTF-8”),将字节数组按照UTF-8的格式,每3个⼀组进⾏解码,才能还原为客户端的原始字符。
.getBytes(“ISO-8859-1”);//第⼀次解码,转换为电脑能够识别的语⾔,
new String(1234,“UTF-8”);//第⼆次解码,转换为我们认识的语⾔
四、Servlet相关的⼏种乱码
1、 浏览器调⽤jsp,html等页⾯中⽂显⽰乱码
解决这类乱码需要满⾜两个要求:
1)⽂件本⾝是以utf-8编辑保存的(myEclipse中在properties中⿏标右键选择utf-8)
2)浏览器⽤utf-8解析:
(⼿动)==> 在浏览器中右键选择编码格式为utf-8
(智能)==> 在⽂件中写⼊如: 通过标签模拟response头,起到告诉浏览器⽤utf-8的编码解析
(智能)==> response.setContentType(“text/html;charset=UTF-8”);起到告诉浏览器⽤utf-8的编码解析
常⽤:
<meta name="content-type" content="text/html; charset=UTF-8">或<meta charset="utf-8">
<%@ pageEncoding="utf-8"%>
<?xml encoding="UTF-8"?>
url编码和utf8区别2、通过浏览器调⽤servlet,页⾯显⽰乱码。
Servlet乱码分为request乱码和response乱码:
(1)response响应回浏览器出现的中⽂乱码:
⾸先介绍⼀下,response对象是如何向浏览器发送数据的。两种⽅法,⼀种getOutputStream,⼀种getWriter。
1)ServletOutputStream getOutputStream(); //获取输出字节流。提供write() 和 print() 两个输出⽅法
2)PrintWriter getWriter(); //获取输出字符流 提供write() 和 print()两个输出⽅法
print()⽅法底层都是使⽤write()⽅法的,相当于print()⽅法就是将write()⽅法进⾏了封装,使开发者更⽅便快捷的使⽤,想输出什么,就直接选择合适的print()⽅法,⽽不⽤考虑如何转换字节。
1、ServeltOutputStream getOutputStream();不能直接输出中⽂,直接输出中⽂会报异常
解决:
要输出的汉字先⽤UTF-8进⾏编码,⽽不⽤让tomcat来进⾏编码,这样如果浏览器⽤的是UTF-8码表进⾏解码的话,那么就会正确输出,如果浏览器⽤的不是UTF-8,那么还是会出现乱码,所以说这个关键要看浏览器⽤的什么码表,这个就不太好,这⾥还要注意⼀点,就是使⽤的是write(byte)⽅法,因为print()⽅法没有输出byte类型的⽅法。
注意:response.setContentType 等效于 response.setCharacterEncoding + response.setHeader
解决⽅法:
⽅法⼀:response.setContentType(“text/html;charset=uft-8”);
使⽤Servlet API 来通知tomcaat和强制浏览器使⽤UTF-8来进⾏编码解码,这个的底层代码就是 response.setCharacterEncoding + response.setHeader的代码,进⾏了简单的封装⽽已。
/*
通过设置响应头,来设置浏览器也使⽤UTF-8字符集⽬的是为了控制浏览器的⾏为,即控制浏览器⽤UTF-8进⾏解码
response.setContentType 等效于 response.setCharacterEncoding + response.setHeader
因为在setContentType⽅法中已经调⽤了setCharacterEncoding⽅法设置了Response容器的编码了。
注意:
2.还设置了响应头
3.调⽤response.setCharacterEncoding 和 response.setContentType⽅法,
必须在getWriter执⾏之前或者response被提交之前,否则依旧会出现乱码问题
*/
response.setContentType("text/html;charset=UTF-8");
⽅法⼆:使⽤Servlet API response.setCharacterEncoding(“UTF-8”);
让tomcat将我们要响应到浏览器的中⽂⽤UTF-8进⾏编码,⽽不使⽤默认的ISO-8859-1了,这个还是要取决于浏览器是不是⽤的UTF-8的码表,跟上⾯的⼀样有缺陷,
所以需要配合response.setHeader(“Content-Type”,“text/html;charset=UTF-8”);来使⽤,作⽤为⼿动设置响应内容,通知tomcat和浏览器使⽤utf-8来进⾏编码和解码。
/*
response.setCharacterEncoding("UTF-8"):设置服务器的响应对象所采⽤的字符编码类型为UTF-8,即设置服务器字符集为UTF-8⽬的是⽤于解决Writer()输出的字符流的乱码问题。
*/
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type","text/html;charset=UTF-8");
(setHeader是HttpServletResponse的⽅法。如果想在Filter中设置字符编码,则⽆此⽅法,因为Filter的doFilter⽅法的参数类型是ServletResponse)
这⾥有⼏个⼩细节需要注意:
1. response.setCharacterEncoding(“UTF-8”);需要写在PrintWriter out = Writer();的前⾯。拿到字符流后再设置
编码是没有⽤的。
2. response.setContentType(“text/html;charset=UTF-8”);这句代码其实有两个作⽤:通知response以UTF-8输出和浏览器以
UTF-8打开。即等价于response.setHeader(“content-type”, “text/html;charset=UTF-8”);和
response.setCharacterEncoding(“UTF-8”);两句代码。
3. response.setContentType(“text/html;charset=UTF-8”); ⽬的是为了控制浏览器的⾏为,即控制浏览器⽤UTF-8进⾏解码;
4. response.setCharacterEncoding(“UTF-8”);⽬的是⽤于Writer()输出的字符流的乱码问题。如果是
(2)request乱码问题
request请求分为post和get,对于不同的请求⽅式有不同的解决乱码的⽅案
第⼀种:POST请求
post请求⽅式的参数是在请求体中,相对于get请求简单很多,没有经过http协议这⼀步的编码过程,所以只需要在服务器端,设置服务器解码的码表跟浏览器编码的码表是⼀样的就⾏了,在这⾥浏览器使⽤的是UTF-8码表编码,那么服务器端就设置解码所⽤码表也为UTF-8就OK了
解决⽅案:
request.setCharacterEncoding(“UTF-8”);//命令Tomcat使⽤UTF-8码表解码,⽽不⽤默认的ISO-8859-1了。
所以在很多时候,在doPost⽅法的第⼀句,就是这句代码,防⽌获取请求参数时乱码。
注意:该设置只对post请求有效
第⼆种:GET请求(URI⽅式传递参数乱码),TOMCAT 8.0 以上⽤ GET ⽅式请求已经不存在乱码问题
get请求的参数是在url后⾯提交过来的,也就是在请求⾏中
FormServlet是⼀个普通的Servlet,浏览器访问它时,使⽤get请求⽅式提交了⼀个name=⼩明的参数值,在doGet中获取该参数值,并且打印到控制台,发现出现乱码
法⼀:要解决这个问题,修改tomcat服务器的配置⽂件。
[注意] TOMCAT 8.0 以上⽤ GET ⽅式请求,传送的参数已默认为 UTF-8 编码,所以可以不需要修改配置⽂件
修改tomcat⽬录下的l⽂件的第69⾏:
修改前内容:
<Connector port="8080"protocol="HTTP/1.1"
maxThreads="150"connectionTimeout="200000"
redirecPort="8443"/>
修改后内容:
<Connector port="8080"protocol="HTTP/1.1"
maxThreads="150"connectionTimeout="200000"
redirecPort="8443"URIEncoding="utf-8"/>
法⼆:
String username= Parameter(“name”);
String usernameString = new Bytes(“ISO-8859-1”),“UTF-8”);
tomcat默认全部都是⽤ISO-8859-1编码,不管你页⾯⽤什么显⽰,Tomcat最终还是会替你将所有字符转做ISO-8859-1.那么,当在另⽬标页⾯再⽤GBK翻译时就会将本来错的编码翻译成GBK的编码,这时的⽂字会乱码.
2.http协议不会对请求参数进⾏编解码!只是传输,传输的是⼆进制。解码是tomcat的⼯作,utf8编码的字节序列被tomcat默认以
iso8895-1⽅式解码所以有了乱码,所以要重新编码再解码。
a. 所以需要先将得到"字符"(不管是什么)都先⽤字节数组表⽰,
b. 且使⽤ISO-8859-1进⾏翻译,得到⼀个在ISO-8859-1编码环境下的字节数组.例如:AB表⽰成[64,65].
c. 然后再⽤GBK编码这个数组,并翻译成⼀个字符串.
那么我们可以得到⼀个编码转换的过程
假设:GBK码(“你”)->URLencode后变成->(%3F%2F)->Tomcat⾃动替你转⼀次ISO-8859-1->得到( 23 43 68 23 42 68 每⼀个符号表⽰为ISO-8859-1中的⼀个编码)->接收页⾯—>再转⼀次为ISO-8859-1的Byte数组[23,43,68,23,42,68]—>⽤GBK再转为可读的⽂字—>(%3F%2F"---->转为(“你”)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论