Tomcat字符编码的常见问题Word文档下载推荐.docx
- 文档编号:22070037
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:13
- 大小:123.76KB
Tomcat字符编码的常见问题Word文档下载推荐.docx
《Tomcat字符编码的常见问题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Tomcat字符编码的常见问题Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
%>
!
DOCTYPEHTMLPUBLIC"
-//W3C//DTDHTML4.01Transitional//EN"
>
html>
<
head>
title>
Characterencodingtestpage<
/title>
/head>
body>
p>
Datapostedtothisformwas:
%
request.setCharacterEncoding("
);
out.print(request.getParameter("
mydata"
));
/p>
formmethod="
POST"
action="
index.jsp"
inputtype="
text"
name="
submit"
value="
Submit"
/>
reset"
Reset"
/form>
/body>
/html>
5.我如何在HTTPHeader中发送高位字符?
你必须在插入到header之前使用某种方式对其编码。
使用url-encoding(%+highbytenumber+lowbytenumber)是一个好的方法。
6.如何确保其正确运行,请给个建议。
使用UTF-8作为字符编码是一个好的办法,这在大多数情况下工作良好。
为了确保完全使用UTF-8,你需要做如下改变:
1.在server.xml中为你的<
Connector>
设置URIEncoding="
2.使用上面Tomcat例子提供的字符编码过滤器保证默认的编码为UTF-8
3.改变所有JSP页面的Content-Type类型为UTF-8(使用<
%@pagecotnentType="
mime/type;
)
4.把所有servlets的Content-Type设置为UTF-8
5.改变你用来生成内容的类库(如Velocity,Freemarker,等等.)的Content-Type为UTF-8
深入理解tomcat处理编码的机制
2010年09月21日星期二上午3:
09
本文从tomcat源码的鲜为人知的UDecoder类入手,试图讲解Tomcat内部处理编码的机制。
只涉及Tomcat处理请求的编码机制,不涉及响应的编码机制。
1.关于UDecoder类
查看tomcat5和tomcat6版本的源码,可以看到org.apache.tomcat.util.buf.UDecoder类。
这个类有什么特别的地方呢?
用简单的一句话概括UDecoder类做的事情:
修改所输入的字节流,将每3个以百分号%开头的字节(如“%HH”,占3个字节),转换成1个十六进制的字节码(如“0xHH”,占1个字节),且将加号"
+"
变成空格“”。
如图举例描述了6个以百分号%开头的字节“%D6%D0”变成了2个十六进制的字节码“[0xD6][0xD0]”。
(注:
我用中括号“[]”来表示其中的内容代表的是1个十六进制形式的字节,下同。
我们知道UDecoder类的功能后,进一步想知道的是,tomcat用这个类做了什么事情?
答案是:
用于修改http请求中的表单参数的值,将每1个“%HH”(占3个字节)变成“0xHH”(占1个字节),且将加号"
(占1个字节)变成空格“”(占1个字节)。
其中表单参数包括:
get方式的url参数和post方式的application/x-www-form-urlencoded的参数。
举个例子,当我们访问这样的url时,
第1点,我们了解UDecoder类就好,继续看第2点。
2.关于tomcat的CharacterEncoding(参考http:
//wiki.apache.org/tomcat/FAQ/CharacterEncoding)
我们使用tomcat时知道,要用request.getParameter("
keywords"
)来获取get或post的参数值,而当keywords不是ISO-8859-1编码的字符时,为了获取到正确的keywords值,我们知道有以下几种方式可以解决(假设参数以GBK编码):
第一种:
自己编程实现转换:
StringISOkeywords=request.getParameter("
//ISOkeywords是乱码
Stringkeywords=newString(ISOkeywords.getBytes("
ISO-8859-1"
),"
GBK"
//keywords=“啤酒”
第二种:
设置${tomcat_home}/config/server.xml中的URIEncode配置项的值为“GBK”
第三种:
设置${tomcat_home}/config/server.xml中的useBodyEncodingForURI配置项的值为true,并实现一个SetCharacterEncodingFilter.java,在tomcat的目录webapps/servlets-examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java中存在这个范例。
3.结合UDecoder和CharacterEncoding,分析访问
tomcat的处理流程大致可以看作以下四个步骤(具体可参见本文最后的流程图):
(1)访问
(2)UDecoder将%C6%A1%BE%C6转换为[0xC6][0xA1][0xBE][0xC6],tomcat持有变量bytes=[0xC6][0xA1][0xBE][0xC6]。
(3)如果设置了URIEncode配置项或者useBodyEncodingForURI配置项为“GBK”,则tomcat会做以下转换:
StringgbkKeywords=newString(bytes,"
//bytes=[0xC6][0xA1][0xBE][0xC6],gbkKeywords=“啤酒”
程序员使用request.getParameter("
)得到的就是上面的gbkKeywords,因此是正确的关键字“啤酒”。
如下图。
(4)如果未设置了URIEncode配置项或者useBodyEncodingForURI配置项,则tomcat相当于执行了以下转换:
Stringkeywords=newString(bytes,"
//bytes=[0xC6][0xA1][0xBE][0xC6],keywords是乱码
)得到的就是上面的keywords,因此是乱码。
所以,此时我们需要自己编程实现转换:
StringisoKeywords=request.getParameter("
//isoKeywords是乱码
Stringkeywords=newString(isoKeywords.getBytes("
4.UDecoder带来的启发
(1)使用UDecoder,可以使得经过URLEncoding和未经过URLEncoding的请求都正确的得到解析。
当然,前提是,未经过经过URLEncoding的URL编码和未经过URLEncoding的请求的字节码的编码是同样的一种编码,如都是GBK或UTF-8。
如
和
想象一下,假如没有UDecoder,那么如果要正确处理keywords=%C6%A1%BE%C6和keywords=[0xC6][0xA1][0xBE][0xC6],tomcat就必须分2种情况去处理:
当keywords=%C6%A1%BE%C6时,tomcat获得字符串“%C6%A1%BE%C6”,然后使用URLDecoder.decode("
%C6%A1%BE%C6"
)得到“啤酒”;
当keywords=[0xC6][0xA1][0xBE][0xC6]时,tomcat直接获取字节码bytes=[0xC6][0xA1][0xBE][0xC6],然后使用newString(bytes,"
得到“啤酒”;
这样远远没有UDecoder的实现那么美观和简单。
20101021补充,总结一下,在写Servlet时,应该怎么做:
(1)如果URIEncoding=“ISO-8859-1”,而浏览器的keywords可能是中文或urlencoding的,好像这样也行:
(这种只针对我部门的开发环境)
Stringkeywords=request.getParameter("
//"
?
"
或"
Stringkeywords2=newString(keywords.getBytes("
),"
//“中文”或"
Stringkeywords3=URLDecoder.decode(keywords2,"
//“中文”
(这种针对tomcat,配置了URIEncoding=“ISO-8859-1”,tomcat)
(2)如果未知URIEncoding=“GBK”还是“ISO-8859-1”,已知浏览器的keywords是urlencoding的:
中文"
Stringkeywords2=URLDecoder.decode(keywords2,"
(3)如果未知URIEncoding=“GBK”还是“ISO-8859-1”,已知浏览器的keywords是中文的:
//则不行!
(4)如果URIEncoding=“GBK”,而浏览器的keywords可能是中文或urlencoding的:
//“中文”这样即可。
(4)是我们推荐使用的,
(1)在没使用tomcat或者不希望应用和容器相关时,使用。
另外,其实.URLDecoder和UDecoder是类似的,不过URLDecoder是缺陷的。
URLDecoder.decode的参数是String,它通过
str.charAt()来解码%HH->
[0xHH],然后newString(bytes,0,pos,enc).而UDecoder.decode()
的参数是字节数组。
区别看出来了吗?
URLDecoder.decode("
)时,charAt是什么,是“?
”,结果还是
URLDecoder.decode("
)="
.而UDecoder.decode(字节数组)是可以正确解码的。
(2)为了SEO,有些网站会将参数放到pathInfo中,对于pathInfo的参数解析,我们也可以模仿UDecoder机制。
据说前段时间XX爬虫访问阿里巴巴时使用的url就是未URLEncoding的(例如
5.最后附上一张图,作为总结。
图是有问题的,form的enctype=content-type取值有:
如multipart/form-data和application/x-www-form-urlencoded
其中multipart/form-data的情况,是指分多个部分,每个部分都有自己的content-type,且默认也是application/x-www-form-urlencoded
。
可以详细见这里
http:
//www.w3.org/TR/html4/interact/forms.html#form-content-type
Tomcat处理编码的流程(有废话有点啰嗦未完成版)
2010年09月20日星期一下午8:
40
请看这篇吧各位--->
深入理解tomcat处理编码的机制
Tomcat是如何处理query/post的编码问题的?
首先我们看看get方式时,tomcat如何获取querystring。
比如我们的url是:
(其中%C6%A1%BE%C6是啤酒的GBK的URLEncode编码)
当请求来到服务器的tomcat(也可以说是Servlet)这一层面时,我们可以通过request获取这个keywords。
获取的方式有两种:
(1)直接使用getParameter("
)得到keywords参数
(2)先使用getQueryString(),再手动解析出keywords参数
我们看看这两种方式。
(1)getParameter("
这里涉及config/server.xml中URIEncode的配置项,假设我没对tomcat作任何URIEncoding的配置,它默认使用ISO-8859-1的编码。
当访问http:
//localhost/?
keywords=%C6%A1%BE%C6后,我们试图打印出getParameter("
)的值,你猜看到什么?
乱码!
我们试图质问tomcat:
“为什么是乱码?
!
如果我输入的keywords是“啤酒”这样的字符,得到乱码我可以接受,但是我输入的可是“%C6%A1%BE%C6”这样一串ISO-8859-1编码的字符啊!
有人猜测,那是浏览器在搞鬼,浏览器发送的不是“%C6%A1%BE%C6”这样的可见字符的,而是发送“啤酒”这个非ascii字符(当然,我们应该理解本质上传送的“啤酒”肯定是“啤酒”的某某编码格式的字节码,这个编码可以是常见的GBK或UTF-8)。
但是,其实不是浏览器搞鬼,浏览器发送的就是“%C6%A1%BE%C6”,你可以通过打印request.getQueryString();
看到,它输出“keywords=%C6%A1%BE%C6”。
那到底是怎么回事呢?
源于tomcat对表单提交的参数(包括Get方式和Post方式)有个UDecode类的处理过程。
什么是UDecode类的处理过程,详细你可以看tomcat源码的UDecode类,这里用简单的一句话概括UDecode类做的事情:
修改request中的parameter(包括get方式的url参数的value和post方式的application/x-www-form-urlencoded的参数的value)的字节,将每1个“%HH”(占3个字节)变成“0xHH”(占1个字节),且将加号"
下面的图直观的描述了这个UDecode过程:
我们看到6个字节的“%D6%D0”变成了2个字节的“[0xD6][0xD0]”,我用中括号“[]”来表示其中的内容合起来是一个字节。
到这里,我们至少知道了tomcat有个UDecode的过程,所以我们从中推理出这样的一个现象:
客户端发送的keywords参数无论是啤酒的GBK字节码“[0xC6][0xA1][0xBE][0xC6]”还是啤酒的GBKURLEncode字符“%C6%A1%BE%C6”,经过tomcat的UDecode后,到变成前者,即“[0xC6][0xA1][0xBE][0xC6]”。
说到这,我再次问上面一开始的那个问题:
getParameter("
)的值为什么是乱码?
我给个提示:
和UDecode有关!
答案现在还不是很明显,但我们脑海可能浮现了这幅图:
从UDecode的结果“[0xC6][0xA1][0xBE][0xC6]”到getParameter("
)的乱码。
你想到问号的部分是什么吗?
很抽象地为你解开答案:
所以,getParameter("
因为上面的bytes是GBK的字节码,而tomcat错误地将bytes作为ISO-8859-1进行解码了!
难怪keywords会是乱码!
这...是tomcat的错吗?
坦诚说不是,因为上面“Stringkeywords=newString(bytes,"
”中的编码"
是可配置的,大家还记得config/server.xml中的URIEncode配置项吧?
就是这个URIEncode配置项,决定是上面的式子用什么编码。
到了这里,大家都清楚了,设置配置项URIEncode=“GBK”就可以用getParameter("
)得到正确的keywords:
“啤酒”。
另外配置项useBodyEncodingForURI使得
http:
//wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q2
-------------------------------------------------------------------------------------------------------------------------
现在,我问大家一个问题,当你知道,浏览器无论访问“http:
keywords=%C6%A1%BE%C6”还是“http:
keywords=[0xC6][0xA1][0xBE][0xC6]”,tomcat都会将keywords变成“[0xC6][0xA1][0xBE][0xC6]”后,大家觉得要怎么去解码还原keywords为“啤酒”呢?
相信答案大家都很一致:
byte[]bit=newbyte[]{(byte)0xD6,(byte)0xD0};
"
中"
的字节码,是URLDecode之后的字节码
Stringw=newString(bit,"
用配置的URIEncoding将其解码,变成字符"
Stringkeywords=null;
request.getQueryString();
//keywords=%C6%A1%BE%C6
if(StringUtil.isNotBlank(ISOkeywords)){
try{
keywords=newString(ISOkeywords.getBytes("
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Tomcat 字符 编码 常见问题