JSP/Servlet中的乱码问题
来源:互联网 发布:淘宝售后处理 编辑:程序博客网 时间:2024/03/29 01:49
近来写一个小程序被中文乱码问题所困扰,不胜其烦,所以下定决心搞清楚其中的“秘密”。本文是参考网上多篇文章,加上自己的理解写成的,希望对像我一样想搞清这个问题的朋友有点帮助。
一、编码
ASCII码
我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。
上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。
ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
- 非ASCII编码
英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个
- Unicode
正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。
Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。
- Unicode的问题
需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。
- UTF-8
互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。
UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
二、乱码产生的原因及时机
上文说到了现在存在的几种编码方式,因为有了各种不同的编码,这就为乱码的产生“铺平了道路”,用一种方式编码,却用了另一种方式去解码(也有很多的很多文章用“重新编码”,笔者以为“解码”更好懂)这就是产生乱码的根本原因。
现在我们言归正传,看看jsp/servlet中哪些地方可能产生这种编码解码方式不一致:
- JSP编译成Servlet时
众所周知,JSP在服务器上是要先被生成Servlet的。这个过程一般由jsp容器(如Tomcat)完成,当jsp文件是以一种方式编码,而jsp容器又是以另一种方式读取文件时会产生不一致。response.setCharacterEncoding设置是指定jsp容器用哪种编码来解码jsp文件,如果该方法没有被调用则使用pageEncoding变量的设置。
- 浏览器与服务的交互
对于浏览器,在接收服务器数据和发送数据到服务器时所使用的编码是相同的,默认情况下均为JSP页面的 response.setCharacterEncoding参数(或者contentType和pageEncoding参数),我们称其为浏览器编码。response.setCharacterEncoding("UTF-8")>contentType="text/html;charset=UTF-8"服务器,对于发送数据,服务器按照response.setCharacterEncoding—>contentType—>pageEncoding的优先顺序,对要发送的数据进行编码。
对于接收数据,要分三种情况。一种是浏览器直接用URL提交的数据,另外两种是用表单的GET和POST方式提交的数据。
无论使用那种方式提交,如果参数中包含中文,浏览器都会使用当前浏览器编码对其进行URL编码。
对于表单中POST方式提交的数据,只要在接收数据的JSP中正确request.setCharacterEncoding参数,即将对客户端请求进行重新编码的编码设置成浏览器编码,就可以保证得到的参数编码正确。在默认请情况下,浏览器编码就是你在响应该请求的JSP页面中response.setCharacterEncoding设置的值。所以对于POST表单提交的数据,在获得数据的JSP页面中request.setCharacterEncoding要和生成提交该表单的JSP页面的 response.setCharacterEncoding设置成相同的值。
对于URL提交的数据和表单中GET方式提交的数据,在接收数据的JSP中设置 request.setCharacterEncoding参数是不行的,因为在Tomcat5.0中,默认情况下使用ISO-8859-1对URL提交的数据和表单中GET方式提交的数据进行解码,而不使用该参数对URL提交的数据和表单中GET方式提交的数据进行解码。要解决该问题,应该在Tomcat的配置文件的Connector标签中设置useBodyEncodingForURI或者URIEncoding属性,其中 useBodyEncodingForURI参数表示是否用request.setCharacterEncoding参数对URL提交的数据和表单中 GET方式提交的数据进行重新编码,在默认情况下,该参数为false(Tomcat4.0中该参数默认为true);URIEncoding参数指定对所有GET方式请求(包括URL提交的数据和表单中GET方式提交的数据)按统一的方式解码。对于URL提交的数据和表单中GET方式提交的数据,可以修改URIEncoding 参数为浏览器编码或者修改useBodyEncodingForURI为true,并且在获得数据的JSP页面中 request.setCharacterEncoding参数设置成浏览器编码。
三、总结
以Tomcat5.0为WEB服务器时,总结下如何防止中文乱码:
1.对于同一个应用,最好统一编码,推荐为UTF-8,当然GBK也可以。
2.正确设置JSP的pageEncoding参数
3.在所有的JSP/Servlet中设置contentType="text/html;charset=UTF-8"或response.setCharacterEncoding("UTF-8"),从而间接实现对浏览器编码的设置。
4.对于请求,可以使用过滤器或者在每个JSP/Servlet中设置request.setCharacterEncoding ("UTF-8")。同时,要修改Tomcat的默认配置,推荐将useBodyEncodingForURI参数设置为true,也可以将 URIEncoding参数设置为UTF-8(有可能影响其他应用,所以不推荐- JSP/Servlet中的乱码问题
- JSP+servlet中的中文乱码问题
- jsp和Servlet中的乱码问题
- JSP+Servlet乱码问题
- jsp/servlet乱码问题
- jsp跳转至servlet中的中文乱码问题
- servlet中的乱码问题
- servlet中的乱码问题
- servlet中的乱码问题
- jsp-servlet的乱码问题
- JSP +SERVLET中文乱码问题
- jsp/servlet中文乱码问题
- servlet+jsp+中文乱码问题
- JSP和Servlet乱码问题
- servlet&jsp 各种乱码问题
- jsp+servlet中乱码问题
- jsp servlet 中文乱码问题
- jsp ,servlet 中文乱码问题
- 去掉pdf中的网页链接
- 漫谈ACE与设计模式
- 通过chattr lsattr命令设置Linux文件系统的隐藏权限
- AJAX / AJAX框架 / AJAX.NET (Professional) / ASP.NET AJAX 区别和详解
- 面试的第一道题,用C#写的KMP算法
- JSP/Servlet中的乱码问题
- 新华书店推网售业务对抗当当卓越
- KMP算法详解
- 经典正则表达式
- 常见CPU运算能力对比
- jQuery Study Note 1 - Selectors
- JAVA Web开发中 JSP隐式对象
- 构造函数和析构函数
- Attitude (态度)