最近在做项目在写 Http post 的时候发现一个有趣的问题。
使用 Apache 的 HttpComponents 工具开发。
当发起 http post 请求的时候,返回的 HttpResponse 的内容是空的(实际上是有数据的),也就是在bebug的时候看到HttpResponse 的entity中 “content=null” 的字样,人傻了好吧,步骤都OK,代码给没问题,但是就是空!然而还有那么一段代码(代码是直接用的官网的例子),导致一直无法获取数据,如下:
CloseableHttpResponse response = httpclient.execute(request);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
long len = entity.getContentLength();
if (len != -1 ) { // 问题就出在这里
result = EntityUtils.toString(entity, "utf-8");
System.out.println("postXml返回result:" + result);
}
}
} finally {
response.close();
}
解析一下:当content==null时,len是等于 -1 的,由于在获取的HttpResponse 的 entity 中 content = null, 所以代码标明问题的地方(len!= -1)不成立,直接跳过,导致无法进入到 if 代码块中。
解决办法:把 if ( len != -1 ) 这个判断代码去掉,这样直接调用 EntityUtils.toString(entity, "utf-8"); 有趣的东西来了,当调用这句代码的时候 HttpResponse 的 entity 中 content 就有数据了。。。
后面查找资料的时候才知道是怎么回事,记录一下。在apache的论坛下有这样的一个描述
In 4.3, DecompressingEntity is used for decompressing entity of http response. When we call DecompressingEntity.getContent(), an new DeflateInputStream or GZIPInputStream will be created, and the header of compressing part will be read and checked.
InputStream decorate(final InputStream wrapped) throws IOException
{ return new GZIPInputStream(wrapped); }In some cases, we don't really need to decompress it. For example, in "http://baike.baidu.com/search/word?word=httpclient&pic=1&sug=1&enc=utf8" the response state code is 302, it contains header "Content-Encoding:gzip" but without any entity data (It occurs sometimes). In RedirectExec.execute(), we don't read the entity, but in the end, it try to close inputstream by EntityUtils.consume(response.getEntity()). When we call entity.getContent() in EntityUtils.consume(response.getEntity()), an EOFException will be thrown and the redirect can not continue.
In this case, we don't care about the real entity – even if the compress format is not right.
In my opinion, the format should be created and checked ONLY when we need to read the content but not just when closing it. So I wrote LazyDecompressingInputStream as a wrapper and create the DecompressingStream until read() method is called. Then more website will be supported.
引用来源https://issues.apache.org/jira/browse/HTTPCLIENT-1432
文章讲了当entity的内容需要被读取的时候才会去创建输入流,同时作者也讲述了他这样做的目的是为了避免某些情况的异常发生和支持更多的网站。