设为首页 收藏本站
查看: 592|回复: 0

[经验分享] tomcat编码问题根源-2

[复制链接]

尚未签到

发表于 2017-1-23 10:02:05 | 显示全部楼层 |阅读模式
  3.2. 转换过程的参数设置
    在以上的转换过程中可以看到,new String(code, "GB2312");这一处的第二个参数非常重要,它告诉java,这个字符串的原始编码是什么,如果写成其他的编码,必然会发生错误。

    因此,转换过程中的参数,java必须有途径得知正确的参数。 
    举例说,让java从文本文件里面读取一段中文。Java最终得到的字符串肯定是Unicode的,但是它需要程序员告诉它,这个文本文件到底是GB2312的,还是UTF-8的。如果程序员不告诉它,它就会贸然选择一种编码,进行解释,其结果可能就是乱码了
又举例说,如果一个Servlet得到了一个http的请求(request),需要程序员告之,这个请求里面的字符串是UTF-8,GB2312,还是纯粹的英文?当然,在得不到信息的时候,它又会自己胡乱猜一个。

    怎么?你不记得自己在代码里面指定过?对了,也许这就是中文问题的原因。 
    多数应用平台(应用服务器或其他)都不是关心中文问题的人编写的,所以不同的应用平台之间,设置参数的方式并不一样,可以说千奇百怪,甚至根本错误。

    在最新版本的tomcat上,推荐的处理方法涉及4个参数
    1. 网页必须制定http content type
    2. JSP必须制定JSP content type
    3. servlet/jsp的请求,必须设定字符集request.setCharacterEncoding.
    4. 修改tomcat的server.xml文件中URIEncoding的设置
    正如文章开头提到的,不同应用服务器的方式并不一致。前3个参数都是规范规定的,而第4的参数并没有规定,所以不同的服务器要用不同的方法。比如tomcat4不需要这个参数,它会直接使用参数3。

    有人认为修改tomcat的配置文件麻烦,而自己写转码的函数进行处理,这不是一个很好的方法,如果转换服务器,因为服务器本身的处理方式变化了,这段“转码”函数很有可能得到面目全非的结果,比如在tomcat4上。

    这里面似乎存在很多重复,但是没有办法。有时候给一段字符给java,java确实没有办法猜测其字符集。如参数3本来是没有的,J2EE规范认为浏览器提交的数据会描述数据的字符集,但是实际上没有浏览器遵守,所以才不得不引入这个参数。 

    4.中文问题的非技术原因
    以上分析了中文问题出现的技术原因,除此以外,还存在两个不是纯技术方面的因素
  4.1. 错误做法的信心从何而来
    早在几年前的tomcat3年代,网上流传的种种解决方法中,就有一种声称不能给JSP指定字符集,否则会造成乱码。这是一个很奇怪的说法,似乎SUN设计的机制完全错误一样,但是何以有不少人相信并且深受其害呢?
因为中文编码本身的特性,有时候几个错误的操作,反而会得到似乎正确的结果。
比如,“中”的GB2312编码有两个字节D6 D0
    1. 如果要把它作为ISO8859-1来处理,实际上是对应两个字符的,即Ö 和Ð。
    2. 如果不指定用户提交数据的字符集,tomcat会以为提交的是这两个字符。
    3. 经过tomcat处理之后,再次输出到相应页面,tomcat当然仍然以ISO8859-1的方式输出两个字符Ö 和Ð
    4. 这样,客户端得到了ISO8859-1的ÖÐ,也就是和GB2312的“中”一样的两个字节。因此他会觉得,自己提交的数据被正确的处理了。

    实际上这样的做法是非常危险的
    首先,这个时候在tomcat的内部,代表这个数据的String的值不是Unicode的“中”,而是Unicode的Ö和Ð也就是4个字节(不要忘记,java的字符串既不是ISO8859-1,也不是GB2312),尽管把这两个错误的字符转为ISO8859-1的字节输出后得到了似乎正确的结果,但是如果系统中还有其他不是来自于用户输入的字符串呢?比如说来自于数据库?tomcat如果把正确的字符串按照同样的方法处理,自然就会造成乱码。
其次,因为String的内容并不是应用程序要处理的内容本身,甚至连长度都变了,所以很多字符串操作都会出现莫名其妙的错误。

    最简单的例子:
    下载最新的tomcat,运行
    1. 访问 http://localhost/servlets-examples/servlet/RequestParamExample
    2. 点击右键把字符集改成GB2312
    3. 分别在两个框输入中 文
    4. 提交
    5. 得到一个显示乱码的页面(左)
    6. 再点击右键把字符集改成GB2312
    7. “中文”两个字出现了(右)
  结果似乎正确,除了要手工改浏览器字符集以外(某些版本的浏览器并不需要)。但是只要使用调试器,或者直接在代码中打印用户输入的字符,就可以看到,得到的用户输入不是“中文”,而是ÖÐ ÎÄ。
这就是为什么有些应用程序“界面显示正确,但是控制台打印的都是乱码”的原因。当你知道自己看起来正确的系统中正在运行着这些奇怪的字符的时候,该考虑放弃这些错误的“捷径”了
  4.2. 并不可靠的工具和服务器
    习惯上,我们总是认为我们使用的开源工具或者商业服务器是正确的,起码是没有大问题的。这个假设在很多时候正确,但是在中文问题方面,并非如此。别忘了多数软件的作者都是欧美人,他们中的很多并不懂也不关心中文或者其他双字节字符集的问题。因此有些工具或者应用服务器在中文处理方法上模糊不清,或者根本错误(真正可怕的是某些国产商业软件都是错误的)。
    这给我们的工作增加了很多难度,因为你的代码在别人的应用服务器上运行,有时候你必须适应他们代码里面的错误。
有很多工具有提供所谓的转码功能,在你弄清楚它到底是做什么之前,不要贸然使用,起码要做一个备份。已经有不少人使用这种“电子碎纸机”杀死了自己的中文数据。
就连java的规范本身,也存在漏洞,比如String.getBytes()这个函数。其设计就是根本错误的,尽管新版的jdk已经声明废止这个函数,但是很多人还在使用。又如URI的编码方式,servlet规范并没有指出应该如何设置,这才导致了tomcat实用自定义的URIEncoding参数。

    5. 小结
    作为一般的应用开发者,没有必要去深究中文字节的每个转换过程。但是,我们需要记住,中文存在很多种形式,而Java如何处理这些形式,需要程序员告知。
简单的说,最可靠的处理办法,就是保证中文在每一个环节都正确。这并不是废话。如果程序员严格按照规范的推荐,设置所需要的各种参数,最后即使遗漏了什么,也是很容易找到原因的。相反,如果走所谓的捷径,有意的疏漏或者错误设置字符集,或用大串的getBytes()进行可疑的转换,也许可以得到似乎正确的结果,但是当问题出现的时候,就很可能成为死结了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-332375-1-1.html 上篇帖子: tomcat数据源Clob出错! 下篇帖子: 转tomcat server.xml详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表