对DisplayTag、Tomcat中编码问题的总结
关于AppFuse中使用中文编码的问题
这2个月一直被DisplayTag折腾,如果DisplayTag的链接或者排序的列中有汉字,那么排序或者翻页都会查询不到结果或报错(如果你处理的好,可能会显示没有可以显示的数据)。
我一直以为这个问题是因为DisplayTag的开发者们没有考虑到中文的问题,因为项目进度很紧,所以就把排序的功能给屏蔽了,虽然经过了大量的测试,但都没有发现翻页时候也存在这个问题(AppFuse自动生成的页面的默认显示25行,如果超过25行会自动分页),直到前天,测试人员才发现这个问题,按照我的理解要修改DisplayTag的源码,后来又想通过自己写过滤器试试,幸运的是在我动手干之前,先和倦兔聊了几句,结果倦兔说他也遇到过这个问题,指出如果在server.xml中添加URIEncoding="GBK"就可以解决问题,我试了一下,果然可以,但这是为什么呢?
在AppFuse中有一个Spring的过滤器,对请求的编码进行转换,这种做法很通用,即使是在以前,我们自己写这个过滤器也不麻烦,而且这个代码在网上随处可见,难道是Spring的过滤器没有起作用吗?也不是,如果没起作用,那么我在Struts中的Action中通过request.getParmeter接收到参数应该是乱码?而且我记得这种做法在Tomcat4.1.24中没有任何问题,那是为什么?和倦兔讨论了一下,我们都没有找到答案。
于是,我就通过google搜索"URIEncoding",找到一堆文章,我读了几篇文章,其中有一篇提到:Tomcat5中对Post和Get请求不再采用相同的处理策略了,而在Tomcat4中采用的处理策略是相同的。于是我想:"我的提交的请求明明是Post,我又没有用Get请求,那Spring的过滤器就应该起作用,为什么结果会这样呢?",我的一个jsp中的Form的代码如下:
<html:form action="editGj" method="post" styleId="gjForm" focus="mc" onsubmit="return validateGjForm(this)"> 看,我的代码明明是使用的是Post方法,为什么结果不正确呢? 我的跳转到下一页的代码是: <a href="?d-449687-p=2&mc=%D7%A8%D2%B5&; excelname=%D7%A8%D2%B5%C3%FB%B3%C6.xls">下一页</a> 加粗的部分就是我的翻页的链接。如果你立刻就看出了我的问题,那么你就可以不用往下看了,呵呵。如果你没有看出问题,请继续,Come On Baby!!! 我采用的真的是Post方法吗?我的form的提交采用的是Post方法,这是没错的,那么链接采用的是Post方法吗?
不是!!!!它采用的是Get方法进行提交的,这就是问题的答案了! Post和Get提交有什么区别吗?
简单的说:Post是将地址传送一次,将form的数据单独提交,而Get则是将地址和参数一起传送,传送的不止是form的数据,但传送的数据的长度有字节限制,另外还有安全问题。如果感兴趣,你可以用google搜一下,会找到很多资料。 当我想到这个区别时,我又检查了一下我的显示列表的页面,发现这个页面没有form,只有,这说明我的提交的确是Get的,于是,Tomcat5对我的Get请求执行的是另外的处理方式,和Post的处理方式不再一样了! Tomcat5对Get请求是怎么处理的? 默认情况下,Tomcat对请求采用的默认编码是ISO-8859-1,我们的JSP页面上声明的
和 <meta http-equiv="Content-Type" content="text/html; charset=GBK"/> 只在显示汉字时有用,而且这2种写法的作用在理论上应该时一致的,但是由于各个软件厂商对Web标准都按照自己的理解进行了修改,所以,常常这2种写法作用就不一致了,使我们在开发Web程序时备感混乱。如果你想了解详情,请查看《网站重构》一书。
这样我们提交的汉字被认为是ISO-8859-1的编码,所以在程序中接收时显示乱码,如果使用过滤器,在过滤器中调用request.setCharacterEncoding("GBK")的话,那么Post上来的汉字将被认为是GBK编码,而Tomcat5对于Get请求上来的编码并不根据过滤器的设定辨认编码方式,默认的依然是ISO-8859-1,Tomcat5中处理Get请求的源代码如下:
上面的代码中,enc代表Tomcat5中server.xml中Connector部分的URIEnocodeing项设定的值,可以看出,如果没有设定URIEncoding项的话,那么Tomcat5也并没有使用默认的ISO-8859-1编码,而是一段fast conversion,所以,即使你的页面使用默认的编码方式进行编码,然后使用ISO-8859-1进行解码,得到的结果也不对,这可能是Tomcat5的一个Bug。如果想绕过这个Bug,那么只有在server.xml的Connector部分设定URIEncoding的值,根据编码方式指定自己的值,在我的程序中我使用的是GBK,所以我修改后的部分如下: acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" port="80" redirectPort="8443" enableLookups="false" minSpareThreads="25" maxSpareThreads="75" maxThreads="150" maxPostSize="0" URIEncoding="GBK">
这个问题我参考了这篇文章:
http://www.javaworld.com.tw/jute/post/view?age=0&bid=9&ppg=1&sty=1&id=44042&tpg=1 http://www.javaworld.com.tw/jute/post/view?age=0&bid=9&ppg=1&sty=1&id=44042&tpg=1
另外,对于编码解码的问题,我还有一句要说,理论上,如果编码的charset和解码的charset是一致的话,那么就应该没有乱码的问题,但是,对于某些特殊的字符来说,如果采用的charset不对,则可能在解码的时候不能显示,所以要选择好字符集,我推荐在处理简体汉字的时候使用GBK。网上也有推荐UTF-8的,具体使用哪种依情况而定。
以上是我的总结,若有错误,请指正,谢谢!
明天,我就放假了,祝我的朋友们春节快乐,万事胜意!
兔八哥
2005年2月4日14:04
另外,我昨晚看了看Tomcat5自带的Servlet Example中过滤器的实现,其中就有关于处理编码的过滤器SetCharacterEncodingFilter,还有另外一个是处理用户输入的过滤器,叫HTMLFilter,用于将用户输入的字符转化为HTML格式的字符,如将">"转换为">",这个过滤器稍加修改就可以用在自己的项目上了,呵呵! |