【问题标题】:Apache HttpClient response content length returns -1Apache HttpClient 响应内容长度返回 -1
【发布时间】:2013-09-14 15:12:37
【问题描述】:

为什么下面的代码返回-1?好像请求失败了。

public static void main(String[] args)
{
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet("http://www.google.de");

    HttpResponse response;
    try
    {
        response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);

        // Prints -1
        System.out.println(entity.getContentLength());
    }
    catch (ClientProtocolException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        httpGet.releaseConnection();
    }
}

是否可以将响应作为字符串获取?

【问题讨论】:

  • getContentLength 的 Javadoc:内容的字节数,如果未知,则为负数。
  • 有据可查...有什么解决这个问题的建议吗?
  • 为什么需要以内容长度开头?使用响应内容(可能是InputStream)而不是通过这种机制验证响应会更好。
  • 是否可以将响应作为字符串获取? 是的。尝试一些事情,而不是询问codez。

标签: java http apache-httpcomponents


【解决方案1】:

尝试运行

Header[] headers = response.getAllHeaders();
for (Header header : headers) {
    System.out.println(header);
}

它会打印出来

Date: Tue, 10 Sep 2013 19:10:04 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=dad7e2356ddb3b7a:FF=0:TM=1378840204:LM=1378840204:S=vQcLzVPbOOTxfvL4; expires=Thu, 10-Sep-2015 19:10:04 GMT; path=/; domain=.google.de
Set-Cookie: NID=67=S11HcqAV454IGRGMRo-AJpxAPxClJeRs4DRkAJQ5vI3YBh4anN3qS0EVeiYX_4XDTGN-mY86xTBoJ3Ncca7eNSdtGjcaG31pbCOuqsZEQMWwKn-7-6Dnizx395snehdA; expires=Wed, 12-Mar-2014 19:10:04 GMT; path=/; domain=.google.de; HttpOnly
P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic
Transfer-Encoding: chunked

这不是问题,您请求的页面根本没有在其响应中提供Content-Length 标头。因此,HttpEntity#getContentLength() 返回-1。

EntityUtils 有许多方法,其中一些返回String。


最近运行curl 产生

> curl --head http://www.google.de
HTTP/1.1 200 OK
Date: Fri, 03 Apr 2020 15:38:18 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2020-04-03-15; expires=Sun, 03-May-2020 15:38:18 GMT; path=/; domain=.google.de; Secure
Set-Cookie: NID=201=H8GdKY8_vE5Ehy6qSkmQru13HqdGEj2tvZUFqvTDAVBxFoL4POI0swPtfI45v1TBjrJuAAfbcNMUddniIf9HHituCAFwUqmUFMDwxDYK5qUlcWiB1A64OcGp6PTT6LKur2r_3z-ToSvLf8RZhKWdny6E8SaArMpkaOqUEWp4aoQ; expires=Sat, 03-Oct-2020 15:38:18 GMT; path=/; domain=.google.de; HttpOnly
Transfer-Encoding: chunked
Accept-Ranges: none
Vary: Accept-Encoding

标头包含Transfer-Encoding 值chunked。对于chunked,响应包含“块”,前面是它们的长度。 HTTP 客户端使用这些来读取整个响应。

当Transfer-Encoding 的值为chunked 时,不应出现Content-Length 标头的HTTP Specification states,如果存在则必须忽略。

【讨论】:

  • @Accountantم 这些是不相关的问题。对于"http://www.google.de",从上面的标题中可以看出(今天仍然如此,请检查curl),返回的响应是Transfer-Encoding 或chunked。使用chunked,不需要发送Content-Length(实际上HTTP 1/1 Specification 要求如果两个标头都存在,则忽略它)。每个块中都有一个长度。这就是 HTTP 客户端用来读取整个响应的内容。但它不是标题所以它不可用。
  • @Accountantم 我编辑了我的答案以使其更清楚。
【解决方案2】:

如果你真的想在不关心内容的情况下获取内容长度,你可以这样做。

EntityUtils.toByteArray(httpResponse.getEntity()).length

【讨论】:

  • 如果我想同时获得内容和长度怎么办?
【解决方案3】:

请注意响应头名称 Transfer-Encoding。它的值是分块的,这意味着数据是逐块传递的。 Transfer-Encoding: chunked 和 Content-Length 不会同时出现。 有两个原因。

  1. 服务器不希望发送的内容长度。
  2. 或者服务器在刷新大于服务器缓冲区的大数据时不知道内容长度。

所以当没有内容长度标头时,您可以在内容正文之前找到每个分块块的大小。例如:

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Set-Cookie: JSESSIONID=8A7461DDA53B4C4DD0E89D73219CB5F8; Path=/

Content-Type: text/html;charset=UTF-8

Transfer-Encoding: chunked

Date: Wed, 18 Mar 2015 07:10:05 GMT

11

helloworld!

3

123

0

上面的 headers 和 content 告诉我们,有两个块数据。第一个块的大小是 11。第二个块的大小是 3。所以内容长度是 14。

问候, 西辞

【讨论】:

    猜你喜欢
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    相关资源
    最近更新 更多