JavaWeb的编码问题
几种常见的编码格式
@(深入分析java web技术内幕)
计算机存储单元为1byte = 8 bit,可依表示的字符范围0-255个 2^8,人类的语言符号过多,无法用1byte表示。为了解决问题,引入了一个新的char,一个char由多个byte组成,这样就可以表示更多的字符了,而从char到byte必须编码。
编码可以看作是字典,是人类符号与计算机字节相互转化的字典。各类语言都需要自己的编码,常见的编码有下面几种:
1. ASCII
共有128个,一个字节低7位表示。031表示控制字符,32126是打印字符。
2. ISO-8859-1
ASCII的128个字符不够用,ISO组织在ASCII的基础上定制了一系列标准,拓展ASCII。分别为ISO8859-1 ~ ISO8859-15,其中ISO8859-1覆盖了大部分的西欧字符,最为常用。ISO-8859-1仍然是单字节编码,一共可以表示0~255个字符。
3. GB2312
《信息交换用汉子编码字符集基本集》,双字节编码,A1A9 用于表示符号,共682个符号,B0F7表示汉字,包含6763个汉字。
4. GBK
《汉字内码扩展规范》,国家技术监督局为windows95定制的新的汉子内码规范,拓展了GB2312,兼容GB2312,编码范围在8140~FEFE(去掉XX7F)之间,总共有23940个码位,可以表示21003个汉字。双字节编码。
5. GB18030
《信息交换用汉子编码字符集》,它可能是单字节,双字节,四字节编码,与GB2312兼容,虽然 是国家强制标准,但是使用并不广泛。
6.0 Unicode
ISO试图创建一个涵盖所有语言的字典,所以制定了Unicode(Universal Code 统一码 )规范。Unicode是Java和XML的基础。
6.1 UTF-16
UTF-16具体定义了Unicode字符在计算机中的存取方式。UTF-16双字节表示Unicode转化格式,是一种定长表示法,无论什么字符都是用2byte表示,即16bit。UTF-16非常方便,这也是Java以UTF-16作为字符存储格式的重要原因。
6.2 UTF-8
UTF-16虽然使用两个字节表示字符很方便,但是很大一部分的字符无须两个字节来表示,造成了空间的浪费,增大了传输的流量。所以UTF-8针对UTF-16做出了优化,使用变长表示法,,每个编码区域有不同的字码长度,不同类型的字符可以由1-6个字节组成。
规则:
如果一个字节最高位(第八位)为0,表示这是一个ASCII字符(00-7F)
如果一个字节使用 11 开头,连续的11 暗示该字符的字节数,代表UTF-8字符的首字节
如果一个字节使用 10 开头,表示它不是首字节,需要向前查找才能得到当前字符的首字节
Java中需要编码的场景
IO操作
发生编码问题,通常是字符和字节之间的转化问题引起的。在IO流中,提供了OutputStreamWriter和InputStreamReader桥梁类,供字符和字节转化。创建这两个对象都可以指定一个charset参数,从而指定字符编码,解决乱码问题(仍然是使用StreamEncoder)。
内存操作
Java String表示字符串,所以String就提供了转化为字节的方法,比如:
s.getBytes("UTF-8")
。也可以使用charset类:Charset charset = new Charset("utf-8"); ByteBuffer[] bf = charset.encode(str); CharBuffer cf = charse.decode(byteBuffer);
Java 如何编码解码
Java编码类图
Java Web 编码
有IO的地方就会有编码,大部分IO乱码都是网络IO引起的。所有经过网络传输的数据都必须为字节,所以Java序列化必须要实现Serializable接口。
用户发送一个HTTP请求,在URL、Cookies、Parameter上都需要编码。
HTTP请求编码示例:
URL 编解码
示例URL:
path info 和 query string出现了中文
经过URLDecoder后得到如下链接:
查阅编码表发现
E5B08F代表UTF-8 小字
E78CAA代表UTF-8猪字
E5A4A7代表UTF-8大字
E4BEA0代表UTF-8侠字
浏览器根据URL编码规范对URL进行编码,按照某种编码格式(一般为UTF-8)将非ASCII字符编码为16进制数字。然后将每个16进制数字前加上"%",从而完成URL编码。
注意,不同浏览器对URL的编码可能不同
在查阅大部分资料发现,firefox以前的版本中,对url进行编码时,path info 会按照utf-8方式进行编码,而query string 则会按照gbk进行编码。
如果不同浏览器对URL的编码不同,那么后台是如何解码的呢?
以Tomcat为例,在server.xml中配置如下即可解决:
HTTP Header 编码
除了URL上的编码问题,在http header 上页存在编码问题。比如,重定向地址、cookies中都可能存在中文字符。
tomcat在对header解码是在request.getHeader时进行的。具体不再分析
POST 表单提交编码解码
POST表单数据放在http请求体中,当我们在浏览器点击提交按钮时,会根据content-type的charset编码对请求体进行编码。在服务端可以通过contentType进行解码,使用 request.setCharacterEncoding(charset)
进行解码,然后使用 requestParamter()
获取参数值,注意编码设置一定在获取之前。
HTTP BODY 编解码
用户请求的数据已经准备完成,服务器会通过response body返回给客户端,可以使用 response.setCharacterEncoding(cahrset)
对返回的结果进行编码,并且将响应头contentType设置为对应的charset返回给客户端,客户端根据contentType进行解码。如果contentType中没有charset,浏览器则会按照http meta头进行解码,如果没有meta头,浏览器则会按照默认编码进行解码。
JS 编码问题
引入外部js文件
如果引入的js文件中包含字符串输出内容 document.write("小红和小明"
, 如果没有设置charset,就会按照默认的字符编码解析js文件,这样有可能出现乱码问题,我们可以在script标签指定chasert属性:
如果js文件的编码和引用页面编码一致,则可以不用添加chaset属性。
JS URL 编码
js处理URL编码问题,提供了三个有效的函数:
escape()
该函数将传入的要解码的字符串中非ASCII的符号和字符全部转换为Unicode编码值,并在前面加上"%u":
document.write(escape("哈哈"));
得到的结果为%u54C8%u54C8
。从而避免了乱码的问题encodeURI()
encodeURI()是专门针对URL编码的函数,它会将整个URL的字符(除特殊字符、字母)进行UTF-8编码,并在每个码值前加上"%":
encodeURI("http://www.baidu.com/test?a=哈哈")
编码为http://www.baidu.com/test?a=%E5%93%88%E5%93%88
encodeURIComponent
和上面的函数类似,但是该函数会将特殊符号也进行编码。
encodeURIComponent("http://www.baidu.com/test?a=哈哈")
编码为http%3A%2F%2Fwww.baidu.com%2Ftest%3Fa%3D%E5%93%88%E5%93%88
其他需要编码的地方
XML encoding、 jsp page指定
最后更新于
这有帮助吗?