【问题标题】:HttpURLConnection is not returning all headersHttpURLConnection 未返回所有标头
【发布时间】:2016-10-03 18:30:30
【问题描述】:

我正在使用以下代码打印 HTTP 标头。

    URL url = new Url("htttp://example.com/example");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    Map<String, List<String>> map = conn.getHeaderFields();
    for (Map.Entry<String, List<String>> entry : map.entrySet()) {
        System.out.println("Key : " + entry.getKey() +
                " ,Value : " + entry.getValue());
    }

这是输出:

Key : null ,Value : [HTTP/1.1 200 OK]
Key : Accept-Ranges ,Value : [bytes]
Key : Cache-Control ,Value : [max-age=604800, public]
Key : Connection ,Value : [Keep-Alive]
Key : Date ,Value : [Mon, 03 Oct 2016 18:01:06 GMT]
Key : ETag ,Value : ["159eb4-53dce1f957880-gzip"]
Key : Expires ,Value : [Mon, 10 Oct 2016 18:01:06 GMT]
Key : Keep-Alive ,Value : [timeout=5, max=100]
Key : Last-Modified ,Value : [Sat, 01 Oct 2016 13:59:46 GMT]
Key : Server ,Value : [Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4]
Key : Transfer-Encoding ,Value : [chunked]
Key : Vary ,Value : [Accept-Encoding,User-Agent]

现在我正在尝试通过 curl:

$ curl -v -D - http://example.com/example -o /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 111.111.111.111...
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0* Connected to example.com (111.111.111.111) port 80 (#0)
> GET example.com/example HTTP/1.1
> Host: example.com
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Mon, 03 Oct 2016 18:25:11 GMT
Date: Mon, 03 Oct 2016 18:25:11 GMT
< Server: Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4
Server: Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4
< Last-Modified: Sat, 01 Oct 2016 13:59:46 GMT
Last-Modified: Sat, 01 Oct 2016 13:59:46 GMT
< ETag: "159eb4-53dce1f957880"
ETag: "159eb4-53dce1f957880"
< Accept-Ranges: bytes
Accept-Ranges: bytes
< Content-Length: 1416884
Content-Length: 1416884
< Cache-Control: max-age=604800, public
Cache-Control: max-age=604800, public
< Expires: Mon, 10 Oct 2016 18:25:11 GMT
Expires: Mon, 10 Oct 2016 18:25:11 GMT
< Vary: Accept-Encoding,User-Agent
Vary: Accept-Encoding,User-Agent

< 
{ [1080 bytes data]
 30 1383k   30  427k    0     0   116k      0  0:00:11  0:00:03  0:00:08  116k^C

查看 java 输出中如何缺少 Content-Length 标头?为什么会这样?我该如何解决这个问题?

【问题讨论】:

  • 它是通过 API 提供的。没有解决办法,你也不需要。
  • @EJP 为什么我不需要修复?如果服务器发送Content-Length,API 不应该返回Content-Length 吗?
  • 我指的API是getContentLength()(和getContentLengthLong())。
  • 我可以使用www.google.com 重现您的错误,标头在 curl 中可见,但在 Java 代码中不可见
  • @NicolasFilotto 这还不是错误。你能证明标头是在 Java 案例中发送的吗?

标签: java httpurlconnection


【解决方案1】:

Content-Length 丢失,因为服务器以块的形式发送响应。这是预期的行为。查看 Java 响应中的 Transfer-Encoding 标头,这里是 RFC 2616, 4.4 Message Length(参见列表的第 3 项)。

【讨论】:

  • 那么我该如何禁用它呢?
  • @BinoyBabu 恐怕这是不可能的。请参阅此related questionRFC 2616, 3.6.1All HTTP/1.1 applications MUST be able to receive and decode the "chunked" transfer-coding,所以我认为你必须处理这个标题
  • @BinoyBabu RFC 2616, 14.41 表示Many older HTTP/1.0 applications do not understand the Transfer-Encoding header,所以如果您可以配置服务器并且真的希望禁用Transfer-Encoding,您可以将服务器回滚到 HTTP/1.0,但我强烈反对这样做因为您将失去 1.1 的大部分改进,例如 Transfer-Encoding 本身
  • 你是说不可能从 HTTP 1.1 的 headers 中找到内容长度吗?我见过很多程序这样做。
  • @BinoyBabu 而不是观察 Content-Length 标头,您必须通过其他方式找出实体主体的大小,例如下载所有内容并计算八位字节的数量
【解决方案2】:

“内容长度”是自动解析的,可以通过conn.getContentLength()conn.getContentLengthLong() 检索。请参阅https://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html#getContentLengthLong() 了解更多信息。

【讨论】:

  • 我没有解释为什么 content-length 不在标头中,如果标头不存在,这将返回 -1 是这种情况
  • @NicolasFilotto 如果标头未发送,它将返回-1,根据@987654326,这里的情况不是 @输出。
  • @EJP 不,我刚刚用 curl 测试了 www.google.com 我看到 Content-Length 是 258 但是对于 java,这个标头不是列表的一部分,所以当我调用这个方法时我得到 -1
  • @NicolasFilotto 所以在 Java 案例中由于某种原因没有发送。
【解决方案3】:

对于 java 的响应包括在 curl 响应的情况下缺少的“transfer-encoding”标头。此外,当我尝试它时,我的尝试得到了 404(未找到)。当我从我的浏览器尝试它时,我也得到了 404。

我的猜测是你有一个覆盖了example.com 的主机条目,它会循环回你自己的 tomcat 或类似的。你的环境有问题。

这就是我得到的:

    /**
     *
     * <P> jdk-1.8 </P>
     * <PRE>
Key :null || Values :[HTTP/1.1 404 Not Found]
Key :X-Cache || Values :[HIT]
Key :Server || Values :[ECS (ewr/1445)]
Key :Etag || Values :["359670651+gzip+ident"]
Key :Cache-Control || Values :[max-age=604800]
Key :x-ec-custom-error || Values :[1]
Key :Vary || Values :[Accept-Encoding]
Key :Last-Modified || Values :[Fri, 09 Aug 2013 23:54:35 GMT]
Key :Expires || Values :[Mon, 10 Oct 2016 19:20:29 GMT]
Key :Content-Length || Values :[1270]
Key :Date || Values :[Mon, 03 Oct 2016 19:20:29 GMT]
Key :Content-Type || Values :[text/html]
     * </PRE>
     * @param urlStr (http://example.com/example)
     */
    private static void printHeaders(String urlStr) {

        try {
            URL urlRef = new URL(urlStr);
            URLConnection urlConnection = urlRef.openConnection();
            Map<String, List<String>> headerFields = urlConnection.getHeaderFields();

            for (String headerName : headerFields.keySet()) {
                List<String> headerEntry = headerFields.get(headerName);
                System.out.println("Key :"+headerName +" || Values :"+headerEntry);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

【讨论】:

    猜你喜欢
    • 2012-02-15
    • 1970-01-01
    • 2019-01-30
    • 2018-08-02
    • 2017-08-29
    • 2013-05-30
    • 2017-09-02
    • 2020-02-08
    相关资源
    最近更新 更多