




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
httpclient编码/xingyue425/article/details/7258934这几天都在纠结Java Web开发中的中文编码问题。其实,很多Java Web开发者都被中文编码“折磨”过,网络上有大量的讨论。以前我也读过这方面的博文,读完后感觉似乎懂了,好像知道了编码问题的原因和解决方法。但是, 一旦投入到实际开发中,发现自己其实没懂,囧! 连续纠结了几天,总算对前因后果有个清晰地认识,故“略谈”一下。之所以略谈,是因为我并非(也没有能力)完整地阐述Java Web开发的中文编码问题,而是就事论事地总结这几天遇到的问题和收获。问题 使用HttpClient 3.x发送GET或POST请求,请求参数中包含中文。服务器是Tocmat 5.5,通过断点调试,发现Servlet拿到的中文参数是乱码。显然,HttpClient和Tomcat没有就中文参数的编码达成一致。 于是,开始深入HttpClient和Tomcat的代码,结合断点调试,发现中文编码问题并不是想象中的那么简单。术语约定 为了使得描述更加请求,我对本文中出现的“术语”进行约定,避免一词多义引起的歧义。1. Encoding: 编码(动词)2. Decoding: 解码(动词)3. Charset: 编码或解码使用的字符集 另外,编码了的数据必然需要解码,因此encoding和decoding往往是同现的。不过为了叙述简练,下文需要两者同现的地方,仅使用encoding。哪些数据需要encoding? 在研究中文编码问题前,我们首先要弄清一个问题:哪些数据需要encoding? 一个Http请求的数据大致包括URI、Header、和Body三个部分。这三个部分貌似都需要encoding,不过我这次只涉及到URI和Body,因此 就不讨论Header了。 我们一般关心请求参数的中文编码问题。虽然URI Path中也可以包括中文,但是。这不是给自己找麻烦吗? GET的请求参数在QueryString中,是URI的一部分。因此,对于GET请求,我们需要关注,URI是如何encoding的? POST的请求参数在Body中,因此,对于POST请求,我们则需要关注,Body是如何encoding的? 对于HttpClient和Tomcat来说,encoding和decoding本身是很容易的事情,关键是要知道charset是什么?要不通过API进行设置,要不通过配置文件进行配置。麻烦的是,URI和Body的charset还可以不一样,使用不同的方法进行设置和配置。 HttpClient是一个类库,通过自身提供的API对URI和Body的charset进行设置;Tomcat通过配置项和Servlet API,对URI和Body的charset进行设置。HttpClient如何设置charset? 我们先看看如何设置GET请求QueryString的charset,然后看看POST请求Body的charset,最后看看如何获取响应数据的charset。设置GET请求QueryString的charset 我们通过GETMethod的setQueryString方法设置QueryString。setQueryString方法有两种原型,我们分别看看。javaview plaincopy1. publicvoidsetQueryString(NameValuePairparams)2. LOG.trace(enterHttpMethodBase.setQueryString(NameValuePair);3. queryString=EncodingUtil.formUrlEncode(params,UTF-8);4. 原型一以参数键值对的形式设置QueryString,使用固定的UTF-8作为charset,而且做URLEncode。因此,调用原型一之后,HttpClient就不会对QueryString再做任何encoding了。 如果不想使用UTF-8,那么可以使用原型二。javaview plaincopy1. publicvoidsetQueryString(StringqueryString)2. this.queryString=queryString;3. 原型二直接设置QueryString的内容。需要注意的是,queryString参数一定是按照某种charset进行URLEncode之后的字符串。 另外,也可以通过GETMethod的构造函数,直接设置URLEncode之后的uri(包括了QueryString):javaview plaincopy1. publicGetMethod(Stringuri)2. super(uri);3. LOG.trace(enterGetMethod(String);4. setFollowRedirects(true);5. 设置POST请求Body的charset 首先,我们可以在POST请求中的Header中设置Content-Type:javaview plaincopy1. PostMethodmethod=newPostMethod();2. method.addRequestHeader(Content-Type,text/html;charset=UTF-8); 在这里,Body的charset就UTF-8。 其次,如果没有设置Content-Type,我们还可以设置HttpClientParam的ContentCharset:javaview plaincopy1. HttpClienthttpClient=newHttpClient();2. HttpClientParamparams=httpClient.getParams();3. params.setContentCharset(UTF-8); 然后,如果没有设置HttpMethodParams的ContentCharset,我们还可以设置HttpMethodParams的ContentCharset:javaview plaincopy1. PostMethodmethod=newPostMethod();2. HttpMethodParamsparams=method.getParams();3. params.setContentCharset(UTF-8); 这三种设置方法的优先级依次递增,也就是说如果同时设置,则以后面的为准。如果都没有设置,默认charset是ISO-8859-1。响应数据的charset 我们一般使用HttpMethodBase(GETMethod和PostMethod的父类)的getResponseBody系列方法获取响应数据。getResponseBody系列方法包括:javaview plaincopy1. publicbytegetResponseBody()throwsIOException.2. publicbytegetResponseBody(intmaxlen)throwsIOException.3. PublicInputStreamgetResponseBodyAsStream()throwsIOException.4. publicStringgetResponseBodyAsString()throwsIOException.5. publicStringgetResponseBodyAsString(intmaxlen)throwsIOException. 我比较喜欢getResponseBodyAsString方法,因为返回值类型是String,直接可以使用。不过,提到String就必须想到charset。响应数据的charset肯定由Web Server(Tomcat)设置的,HttpMethodBase是怎么知道的呢? 我们看看getResponseBodyAsString()方法的代码:javaview plaincopy1. publicStringgetResponseBodyAsString()throwsIOException2. byterawdata=null;3. if(responseAvailable()4. rawdata=getResponseBody();5. 6. if(rawdata!=null)7. returnEncodingUtil.getString(rawdata,getResponseCharSet();8. else9. returnnull;10. 11. 顾名思义,getResponseCharSet方法的功能就是获取响应数据的charset。那就看看她的代码吧:javaview plaincopy1. publicStringgetResponseCharSet()2. returngetContentCharSet(getResponseHeader(Content-Type);3. 可见,getResponseCharSet方法Content-Type Header获取响应数据的charset。这要求Servlet必须正确设置response的Content-Type Header。Tomcat如何设置charset? 即使HttpClient正确设置了charset,Tomcat还要知道charset是什么,才能正确decoding。我们先看看如何设置GET请求QueryString的charset,然后看看POST请求Body的charset,最后看看Servlet响应数据的charset。设置GET请求QueryString的charset Tomcat通过URI的charset来设置QueryString的charset。我们可以在Tomcat根目录下conf/server.xml中进行配置。xhtmlview plaincopy1. URIEncoding属性就是URI的charset,上述配置表示 Tomcat认为URI的charset就是UTF-8。如果HttpClient也使用UTF-8作为QueryString的charset,那么 Tomcat就可以正确decoding。详情可以参考org.apache.tomcat.util.http.Parameters类的handleQueryParameters的方法:javaview plaincopy1. /-Processing-2. /*Processthequerystringintoparameters3. */4. publicvoidhandleQueryParameters()5. /省略部分代码6. processParameters(decodedQuery,queryStringEncoding);7. Tomcat在启动的过程中,如果从conf/server.xml中读取到URIEncoding属性,就会设置queryStringEncoding的值。当Tomcat处理HTTP请求时,上述方法就会被调用。默认的server.xml是没有配置URIEncoding属性的,需要我们手动设置。如果没有设置,Tomcat就会采用一种称为“fast conversion”的方式解析QueryString。详情可以参考org.apache.tomcat.util.http.Parameter类的urlDecode方法。 useBodyEncodingForURI是与URI charset相关的另一个属性。如果该属性的值为true,则Tomcat将使用Body的charset作为URI的charset。下一节将介绍Tomcat如何设置Body的charset。如果Tomcat没有设置Body的charset,那么将使用HTTP请求Content-Type Header中的charset。如果HTTP请求中没有设置Content-Type Header,则使用ISO-8859-1作为默认charset。详情参见org.apache.catalina.connector.Request的parseParmeters方法:javaview plaincopy1. /*2. *Parserequestparameters.3. */4. protectedvoidparseParameters()5. /省略部分代码6. Stringenc=getCharacterEncoding();7. booleanuseBodyEncodingForURI=connector.getUseBodyEncodingForURI();8. if(enc!=null)9. parameters.setEncoding(enc);10. if(useBodyEncodingForURI)11. parameters.setQueryStringEncoding(enc);12. 13. else14. parameters.setEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);15. if(useBodyEncodingForURI)16. parameters.setQueryStringEncoding(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);17. 18. 19. parameters.handleQueryParameters();20. /省略部分代码21. 默认的server.xml是没有配置useBodyEncodingForURI属性的,需要我们手动设置。如果没有设置,Tomcat则认为其值为false。需要注意的是,如果URIEncoding和useBodyEncodingForURI同时设置,而且Body的charset已经设置,那么将以Body的charset为准。设置POST请求Body的charset 设置Body charset的方法很简单,只要调用javax.servlet.ServletRequest接口的setCharacterEncoding方法即可,比如request.setCharacterEncoding(UTF-8)。需要注意的是,该方法必须在读取任何请求参数之前调用,才有效果。详情可以参见该方法的注释:javaview plaincopy1. /*2. *Overridesthenameofthecharacterencodingusedinthebodyofthis3. *request.Thismethodmustbecalledpriortoreadingrequestparameters4. *orreadinginputusinggetReader().5. *6. *7. *paramenvaStringcontainingthenameof8. *thecharacterencoding.9. *throwsjava.io.UnsupportedEncodingExceptionifthisisnotavalidencoding10. */11. publicvoids
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 物流生态构建-洞察及研究
- 化学工业环保治理规定
- 利率市场化浪潮下商业银行利率定价管理的变革与突破
- 教具制造业并购后的国际市场拓展策略研究-洞察及研究
- 招聘效果量化分析-洞察及研究
- 智慧仓储系统构建与应用-洞察及研究
- 物联网平台间的隔离机制-洞察及研究
- 压气机叶片设计创新-洞察及研究
- 义务劳动活动总结9篇
- 新兴市场机遇-洞察及研究
- 2025年检查检验项目分级审核制度
- 河道工程基础井点降水方案
- 2025年柳州市城中区人民法院招录聘用人员考试试题
- 2024年危险化学品典型事故案例反思
- 四川普通高中会考英语试卷及答案
- ISO28000:2022供应链安全管理体系
- MOOC 电工电子实验基础-东南大学 中国大学慕课答案
- 营造林技能竞赛试题及答案
- 计算机专业英语(第二版)整本书课件完整版电子教案(最新)
- 多晶硅还原装置操作规程
- 复旦大学大学物理热学课件Heat-Ch1-partI
评论
0/150
提交评论