`
RednaxelaFX
  • 浏览: 3009486 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

用Apache HttpClient 4.0时强制指定响应的字符编码

    博客分类:
  • Java
阅读更多
前两天一段调用HTTP服务的脚本出了问题,仔细一看,发现是提供的HTTP服务在响应头里写了:
HTTP/1.1 200 OK
Server: xxxxxxxxxx
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length:2014

响应的头中声明了Content-Type,其中指定了charset=utf-8;但实际上响应中的文本却是GBK编码的。这使得原本我写的请求脚本出了问题。

依赖的Apache HttpClient如下:
pom.xml:
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpcomponents-client</artifactId>
  <version>4.0</version>
</dependency>
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpcomponents-core</artifactId>
  <version>4.0.1</version>
</dependency>


原本的脚本使用DefaultHttpClient去发起请求,并通过EntityUtils自己实现一个与BasicResponseHandler相似的ResponseHandler,类似这样的:
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

def httpClient = new DefaultHttpClient();
def makeResponseHandler(charset) {
  { response ->
      def statusLine = response.statusLine;
      if (statusLine.statusCode >= 300) {
        throw new HttpResponseException(statusLine.statusCode, statusLine.reasonPhrase);
      }
      
      def entity = response.entity;
      entity ? EntityUtils.toString(entity, charset) : null;
  } as ResponseHandler
}

def httpGet = new HttpGet(requestUrl);
def responseBody = httpClient.execute(httpGet, makeResponseHandler('GBK'));


原本要调用的那个HTTP服务返回的响应的头里面没有Content-Type,所以这样去使用EntityUtils.toString(entity, defaultCharset)就已经可以达到指定解析响应内容时使用的字符编码的目的了。

问题是那个HTTP服务现在带上了错误的Content-Type,而EntityUtils.toString(entity, defaultCharset)认为Content-Type中的charset比defaultCharset更优先,此时上面的脚本就达不到强制指定字符编码的目的了。

咋办呢?最直观的当然是自己把响应的内容的byte数组拿到手,然后自己想怎么处理就怎么处理:
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

def httpClient = new DefaultHttpClient();
def makeResponseHandler(charset) {
  { response ->
      def statusLine = response.statusLine;
      if (statusLine.statusCode >= 300) {
        throw new HttpResponseException(statusLine.statusCode, statusLine.reasonPhrase);
      }
      
      def entity = response.entity;
      def bytes = entity ? EntityUtils.toByteArray(entity) : null;
      bytes ? new String(bytes, charset) : null;
  } as ResponseHandler
}

def httpGet = new HttpGet(requestUrl);
def responseBody = httpClient.execute(httpGet, makeResponseHandler('GBK'));


不知道还有没有啥更好的办法呢?我对HttpClient还是太不熟悉了。

本来最好自然是提供HTTP服务的那边把响应头的信息修正,但这又要经过各种繁琐的流程,我在跟进的某工具却等不及了,只好hack一下 =_=
分享到:
评论
8 楼 sandssss 2011-01-18  
听说了这个坑爹的案例~~
7 楼 lwwin 2011-01-17  
RednaxelaFX 写道
lwwin 写道
真不好意思,呵呵,下次知道这个做什么用了^-^||
似乎比较类似make工具~

与其说像make,还不如说像…呃,这跟RubyGems也可以算像吧。至少普通的make是不帮忙抓依赖的,而POM会帮忙抓。


抓依赖美~ 以前经常因为依赖太多而又要手动配置心烦……
看到GROOVY语言的时候,水水真希望类C系列也有这么一套东西=x=!
兼容C++,又支持新特性……不知道有没有,以后有没有,C++0X还没看过……
6 楼 RednaxelaFX 2011-01-17  
lwwin 写道
真不好意思,呵呵,下次知道这个做什么用了^-^||
似乎比较类似make工具~

与其说像make,还不如说像…呃,这跟RubyGems也可以算像吧。至少普通的make是不帮忙抓依赖的,而POM会帮忙抓。
5 楼 lwwin 2011-01-17  
RednaxelaFX 写道
lwwin 写道
FX大似乎是主力=v=+ 开发工具什么的?

好像例子里面没有那个POM也可以跑的嘛,关于Maven似乎需要了解一下先~

这年头跟Java程序员说依赖的包是什么,用Maven的POM格式来说也算是流行的做法吧 = =


真不好意思,呵呵,下次知道这个做什么用了^-^||
似乎比较类似make工具~
4 楼 RednaxelaFX 2011-01-17  
lwwin 写道
FX大似乎是主力=v=+ 开发工具什么的?

好像例子里面没有那个POM也可以跑的嘛,关于Maven似乎需要了解一下先~

这年头跟Java程序员说依赖的包是什么,用Maven的POM格式来说也算是流行的做法吧 = =
3 楼 lwwin 2011-01-17  
FX大似乎是主力=v=+ 开发工具什么的?

好像例子里面没有那个POM也可以跑的嘛,关于Maven似乎需要了解一下先~
2 楼 RednaxelaFX 2011-01-16  
lwwin 写道
花了一整天,总算拼凑了个服务器然后跑出你那个问题- -

不过还有一些细节问问:
1) 所谓的“依赖的Apache HttpClient”是在客户端用的XML文件吗?
2) HTTP response 那段是在Groovy的程序里面打印显示的么?(不用抓包)
3) 不知道为啥bat在离开以后,里面设置的环境变量会被撤销……
@SETLOCAL ENABLEEXTENSIONS
@SETLOCAL ENABLEDELAYEDEXPANSION
@set "GROOVYPATH=."
@call path\add_classpath.bat E:\jLIBs\ApacheClient\httpcomponents-core-4.1\lib
@call path\add_classpath.bat E:\jLIBs\ApacheClient\httpcomponents-client-4.0.3\lib
::@echo current path : %GROOVYPATH%

在这里面打印echo是OK的,但是离开这个BAT以后似乎GROOVYPATH被重置了……

1) 那两段XML片段是Maven的POM配置文件的依赖声明
2) 是用curl -D来抓取的
3) 唔,BAT我一直不够熟悉,回答不了…
1 楼 lwwin 2011-01-16  
花了一整天,总算拼凑了个服务器然后跑出你那个问题- -

不过还有一些细节问问:
1) 所谓的“依赖的Apache HttpClient”是在客户端用的XML文件吗?
2) HTTP response 那段是在Groovy的程序里面打印显示的么?(不用抓包)
3) 不知道为啥bat在离开以后,里面设置的环境变量会被撤销……
@SETLOCAL ENABLEEXTENSIONS
@SETLOCAL ENABLEDELAYEDEXPANSION
@set "GROOVYPATH=."
@call path\add_classpath.bat E:\jLIBs\ApacheClient\httpcomponents-core-4.1\lib
@call path\add_classpath.bat E:\jLIBs\ApacheClient\httpcomponents-client-4.0.3\lib
::@echo current path : %GROOVYPATH%

在这里面打印echo是OK的,但是离开这个BAT以后似乎GROOVYPATH被重置了……

相关推荐

Global site tag (gtag.js) - Google Analytics