WEB容器切换编码问题分享

来源:互联网 发布:mars毒药君淘宝网店 编辑:程序博客网 时间:2024/06/01 22:27

这两天在处理应用从Jetty迁移至Tomcat容器出现的乱码问题时,我理了一下编码相关的问题,整理出来备忘,也顺便给大家分享。

1.    先普及一下编码知识:

如大家所知互联网或者本地数据都是基于二进制来进行传输和存储,而在双方相互通讯时具体哪些二进制数代表哪些字符,那就需要一个大家都达成统一共识的编码规则。

ü ASCII: 最早的计算机编码是由ANSI定制的ASCII编码,该编码是单字节编码,使用7位二进制数表示128个可能的字符,适用于当时的所有拉丁文字字符。

 

ü ISO-8859-1: 同样使用8位单字节来储存,是ASCII码的升级,除了兼容7位ASCII码以外,增加了其他语言符号的支持。由于是单字节编码,通过ISO8859-1编码的字符在解码的时候都不会被丢失,换言之,所有编码的字节流都可以通过ISO8859-1来传输或者存储,这一点对于网关实现商户字符集兼容非常关键,后面会讲到!

 

ü GB2312/GBK: GB2312是专门用来表示中文汉字的编码,是16位双字节编码,其中英文字母部分和ASCII和ISO-8859-1一致。另外GBK是兼容GB2312的繁体字编码。

 

ü UNICODE: UNICODE的出现之目的是要解决不同编码之间的统一存储和处理问题,UNICODE用定长8位双字节来编码,是最统一的编码,可以表示所有语言的字符。所以很多软件内部都是基于UNICODE来处理的,包括JAVA。

 

ü UTF: UTF几乎可以支持所有语言的编码,考虑到UNICODE是定长双字节很占用空间,UTF采用不定长编码,占用1-6个字节,对于英文字母采用单字节编码,而中文采用三个字节来编码。总体来说汉字的UTF网页还是要比Unicode的节省空间,因为包含了很多英文字符。但是相比较如果大部分是汉字的话,采用双字节的GB2312要比UTF-8更节省空间。

 

2.    浏览器和Web Server之间的交互:

POST方式

浏览器端发送:

提交数据首先按照页面设定的Chaset字符集来进行编码传输。

 

WebServer端接收:

所有的数据转码基本上在不同容器的request.getParameter()和request.getParameteMap()等过程中进行,该过程首先会对提交过来的数据流按照一定编码方式来进行解码,最终变成Java的Unicode。

服务器会通过以下几种方式来获取编码方式:

1)  Http Header里面的Context-Type(<%@ pagecontentType="text/html;charset=UTF-8"%>)

2)  Http Header里面的Accept-Charset(form attribute设置)

3)  Request.setCharacterEncoding手工设定的编码方式(注意这个方法必须是在获取第一个参数之前指定,否则不会生效。)

4)  通过各种Charset Filter来指定编码,其原理同第二点,即改变每个Request的Charset。

如果都没有指定,则按照容器默认编码进行解码

注:Tomcat默认编码是ISO-8859-1, 而Jetty的默认编码是UTF-8

 

GET方式

GET方式和POST方式不同的是所有提交数据都是包含在Http Header里面的QueryString(http://XXXX/a.htm?a=1&b=2)里面,而不是Body里面。

浏览器端发送:

QueryString的编码方式基本是取决于系统的编码方式,不同浏览器的处理方式也都不一样。所以GET方式的编码是最难把控的,如果要彻底兼容的话可以在生成QueyString之前通过后端程序或者JS把字符按照指定字符集预先URLEncoding。

 

WebServer端接收:

Get方式的服务端解码编码方式完全取决于容器的配置,Request.setCharacterEncoding对GET方式不会生效。

Jetty:

1)  启动时指定JVM参数:-Dorg.eclipse.jetty.util.URI.charset=UTF-8

2)  Servlet里面手工指定:request.setAttribute("org.mortbay.jetty.Request.queryEncoding","UTF-8");

不指定的话默认用UTF-8

 

Tomcat:

1)  Server.xml <connector>节点增加URIEncoding="UTF-8"

2)  Server.xml <connector>节点增加useBodyEncodingForURI="true" 指定按照POST方式来获取编码

不指定的话默认用ISO-8859-1

 

 

衍生出来的另外两种交互方式:

Redirect:

在返回Response的Header里面增加了浏览器重定向命令,后续的流程同GET方式。

 

Forward:

不会经过浏览器跳转,在服务器内部实现了跳转,第一个Request的Attribute和Parameter都会带入下一个Request,最后做Merge操作。

由于Forward是容器内部的跳转,所有不同的容器处理字符集的实现有所差别。

Jetty:

QueryString的编码方式取决于容器的配置,默认为UTF-8

 

Tomcat:

QueryString的编码方式可以被POST方式的Request.setCharacterEncoding来指定。

*正是由于这个差别,导致了应用这次上线出现的乱码和签名出错问题。

 

3.    兼容商户编码的解决方案


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 凉菜调咸了怎么办 炖芸豆咸了怎么办 铁锅炒菜菜发黑怎么办 红豆沙馅太稀了怎么办 买的豆沙馅太稀怎么办 做的豆馅稀了怎么办 包豆沙包馅稀了怎么办 软件自定义权限重名怎么办 窗户外有垃圾桶怎么办 菜地里有蚂蚁怎么办 灯光吸引的飞虫怎么办 广告机格式化了怎么办 proe约束冲突了怎么办 中午考试想睡觉怎么办 喝了红茶睡不着怎么办 考试前状态不好怎么办 考前紧张睡不着觉怎么办 通宵失眠第二天怎么办 考试前睡不着觉怎么办 一到晚上睡不着怎么办 明天考试听力差怎么办 天天晚上睡不着觉怎么办 因紧张睡不着觉怎么办 房卡找不到了怎么办 马代不会英文怎么办 剩下的蒸米饭怎么办 临时牌照违法了怎么办 打12345不管用怎么办 省政府改变了中央文件怎么办 应聘时学历不够怎么办 做导游学历不够怎么办 市长热线打不通怎么办 12315网站不受理怎么办 法律文书生效前转后财产怎么办 打12345投诉没用怎么办 单位医保停了怎么办 iphonex开不了机怎么办 会计证三年没检怎么办 银行工作人员态度不好怎么办 生殖保健服务证怎么办 关机后自动开机怎么办