Tomcat字符编码的常见问题.docx

上传人:b****7 文档编号:8933879 上传时间:2023-02-02 格式:DOCX 页数:13 大小:123.76KB
下载 相关 举报
Tomcat字符编码的常见问题.docx_第1页
第1页 / 共13页
Tomcat字符编码的常见问题.docx_第2页
第2页 / 共13页
Tomcat字符编码的常见问题.docx_第3页
第3页 / 共13页
Tomcat字符编码的常见问题.docx_第4页
第4页 / 共13页
Tomcat字符编码的常见问题.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

Tomcat字符编码的常见问题.docx

《Tomcat字符编码的常见问题.docx》由会员分享,可在线阅读,更多相关《Tomcat字符编码的常见问题.docx(13页珍藏版)》请在冰豆网上搜索。

Tomcat字符编码的常见问题.docx

Tomcat字符编码的常见问题

Tomcat字符编码的常见问题

1.默认的字符编码是什么?

如果没有指定字符编码,Servlet规范规定使用ISO8859-1作为默认的编码。

2.我怎样改变GET方法的解析?

在server.xml中的Connector中指定URIEncoding参数。

3.我怎样改变POST方法的解析?

POST请求需要指定它发送的参数和值的编码,因为大多数客户端可能没有设置一个明确的编码,默认使用的是ISO8859-1。

大多数情况下它可能不是我们希望的编码,因此可以使用一个javax.servlet.Filter来改变编码。

Tomcat已经提供了完成这个功能的过滤器的例子。

请参看:

4.x

webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java

5.x

webapps/servlets-examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java

webapps/jsp-examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java

6.x

webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java

4.我如何测试我配置工作正常?

下面这个JSP代码能够工作在一个没做任何改变新安装的Tomcat上。

如果你设置了URIEncoding="UTF-8",它也能工作在GET方式上。

<%@pagecontentType="text/html;charset=UTF-8"%>

DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">

Characterencodingtestpage

Datapostedtothisformwas:

<%

request.setCharacterEncoding("UTF-8");

out.print(request.getParameter("mydata"));

%>

5.我如何在HTTPHeader中发送高位字符?

你必须在插入到header之前使用某种方式对其编码。

使用url-encoding(%+highbytenumber+lowbytenumber)是一个好的方法。

6.如何确保其正确运行,请给个建议。

使用UTF-8作为字符编码是一个好的办法,这在大多数情况下工作良好。

为了确保完全使用UTF-8,你需要做如下改变:

1.在server.xml中为你的设置URIEncoding="UTF-8"

2.使用上面Tomcat例子提供的字符编码过滤器保证默认的编码为UTF-8

3.改变所有JSP页面的Content-Type类型为UTF-8(使用<%@pagecotnentType="mime/type;charset=UTF-8"%>)

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("keywords");//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,"GBK");//bytes=[0xC6][0xA1][0xBE][0xC6],gbkKeywords=“啤酒”    程序员使用request.getParameter("keywords")得到的就是上面的gbkKeywords,因此是正确的关键字“啤酒”。

如下图。

  

(4)如果未设置了URIEncode配置项或者useBodyEncodingForURI配置项,则tomcat相当于执行了以下转换:

   Stringkeywords=newString(bytes,"ISO-8859-1");//bytes=[0xC6][0xA1][0xBE][0xC6],keywords是乱码

   程序员使用request.getParameter("keywords")得到的就是上面的keywords,因此是乱码。

如下图。

    

  

  所以,此时我们需要自己编程实现转换:

     

  StringisoKeywords=request.getParameter("keywords");//isoKeywords是乱码

  Stringkeywords=newString(isoKeywords.getBytes("ISO-8859-1"),"GBK");//keywords=“啤酒”

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,"GBK");得到“啤酒”;

  这样远远没有UDecoder的实现那么美观和简单。

20101021补充,总结一下,在写Servlet时,应该怎么做:

 

(1)如果URIEncoding=“ISO-8859-1”,而浏览器的keywords可能是中文或urlencoding的,好像这样也行:

(这种只针对我部门的开发环境)

Stringkeywords=request.getParameter("keywords");//"?

?

?

?

"或"%C6%A1%BE%C6"

Stringkeywords2=newString(keywords.getBytes("ISO-8859-1"),"GBK");//“中文”或"%C6%A1%BE%C6"

Stringkeywords3=URLDecoder.decode(keywords2,"GBK");//“中文”

(这种针对tomcat,配置了URIEncoding=“ISO-8859-1”,tomcat)

 

(2)如果未知URIEncoding=“GBK”还是“ISO-8859-1”,已知浏览器的keywords是urlencoding的:

Stringkeywords=request.getParameter("keywords");//"中文"或"%C6%A1%BE%C6"

Stringkeywords2=URLDecoder.decode(keywords2,"GBK");//“中文”

 (3)如果未知URIEncoding=“GBK”还是“ISO-8859-1”,已知浏览器的keywords是中文的:

Stringkeywords=request.getParameter("keywords");//"中文"或"?

?

?

"

Stringkeywords2=newString(keywords.getBytes("ISO-8859-1"),"GBK");//则不行!

 (4)如果URIEncoding=“GBK”,而浏览器的keywords可能是中文或urlencoding的:

Stringkeywords=request.getParameter("keywords");//“中文”这样即可。

 (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")得到keywords参数

(2)先使用getQueryString(),再手动解析出keywords参数

我们看看这两种方式。

(1)getParameter("keywords")

这里涉及config/server.xml中URIEncode的配置项,假设我没对tomcat作任何URIEncoding的配置,它默认使用ISO-8859-1的编码。

      当访问http:

//localhost/?

keywords=%C6%A1%BE%C6后,我们试图打印出getParameter("keywords")的值,你猜看到什么?

乱码!

我们试图质问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个字节),且将加号"+"(占1个字节)变成空格“”(占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("keywords")的值为什么是乱码?

我给个提示:

和UDecode有关!

答案现在还不是很明显,但我们脑海可能浮现了这幅图:

从UDecode的结果“[0xC6][0xA1][0xBE][0xC6]”到getParameter("keywords")的乱码。

你想到问号的部分是什么吗?

很抽象地为你解开答案:

所以,getParameter("keywords")的值为什么是乱码?

因为上面的bytes是GBK的字节码,而tomcat错误地将bytes作为ISO-8859-1进行解码了!

难怪keywords会是乱码!

这...是tomcat的错吗?

坦诚说不是,因为上面“Stringkeywords=newString(bytes,"ISO-8859-1");”中的编码"ISO-8859-1"是可配置的,大家还记得config/server.xml中的URIEncode配置项吧?

就是这个URIEncode配置项,决定是上面的式子用什么编码。

到了这里,大家都清楚了,设置配置项URIEncode=“GBK”就可以用getParameter("keywords")得到正确的keywords:

“啤酒”。

另外配置项useBodyEncodingForURI使得

http:

//wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q2

-------------------------------------------------------------------------------------------------------------------------

现在,我问大家一个问题,当你知道,浏览器无论访问“http:

//localhost/?

keywords=%C6%A1%BE%C6”还是“http:

//localhost/?

keywords=[0xC6][0xA1][0xBE][0xC6]”,tomcat都会将keywords变成“[0xC6][0xA1][0xBE][0xC6]”后,大家觉得要怎么去解码还原keywords为“啤酒”呢?

相信答案大家都很一致:

byte[]bit=newbyte[]{(byte)0xD6,(byte)0xD0};"中"的字节码,是URLDecode之后的字节码

Stringw=newString(bit,"GBK"); 用配置的URIEncoding将其解码,变成字符"中"

StringISOkeywords=request.getParameter("keywords");

Stringkeywords=null;

request.getQueryString();//keywords=%C6%A1%BE%C6

if(StringUtil.isNotBlank(ISOkeywords)){

try{

keywords=newString(ISOkeywords.getBytes("ISO-8859-1"),"GBK");

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 文学研究

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1