如何在 apache http 客户端中忽略零 content-length header

How to ignore zero content-length header in apache http client

服务器响应 body 是“[]”并且 Content-Length = 0。当客户端尝试读取提到的响应 body 时,它总是一次得到“-1”。此外,如果我拦截服务器响应并将 Content-Length 更改为“2” - 一切正常。我可以得出结论,当 Content-Length = 0 时 apache http client returns -1,但响应 body 实际上不是空的。我正在寻找即使 Content-length 不正确也能够读取响应 body 的解决方法,即我可以设置 http 客户端以忽略 Content-length header 值吗?我没有机会修改服务器,并且由于某些原因我不能使用 HttpUrlConnection 而不是 apache 客户端。拜托,任何建议。

故障Content-length的问题是HttpClient不知道响应何时结束,在Keep-Alive连接的情况下,这也会中断此连接上的下一个请求。 最简单的选择是扩展 org.apache.http.impl.entity.LaxContentLengthStrategy 并使其 return 内容长度为“2”,而在 header 中为“0”,但如果长度真的为 0,线程将挂起等待从套接字中读取更多内容:

class MyLaxContentLengthStrategy extends LaxContentLengthStrategy{
    public long determineLength(final HttpMessage message) throws HttpException {
        final Header contentLengthHeader = message.getFirstHeader(HTTP.CONTENT_LEN);
        if (contentLengthHeader != null) {
            long contentlen = -1;
            final Header[] headers = message.getHeaders(HTTP.CONTENT_LEN);
            for (int i = headers.length - 1; i >= 0; i--) {
                final Header header = headers[i];
                try {
                    contentlen = Long.parseLong(header.getValue());
                    break;
                } catch (final NumberFormatException ignore) {
                }
                // See if we can have better luck with another header, if present
            }
            if (contentlen == 0) {
                return 2;
            }
        }
        return super.determineLength(message);
    }
}

在 HttpClient 中设置 which 可能有点棘手: http://mail-archives.apache.org/mod_mbox/hc-httpclient-users/201301.mbox/%3C1359388867.10617.16.camel@ubuntu%3E 从 4.4 开始就更容易了:

ManagedHttpClientConnectionFactory cliConnFactory = new ManagedHttpClientConnectionFactory(
            null, null, null,
            new MyLaxContentLengthStrategy());

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(cliConnFactory);
HttpClients.custom
.....
.setConnectionManager(cm)
.build(); 

所以如果你真的不需要带“[]”的body,你可以指示HttpClient关闭这个连接并放弃错误的响应。这可以通过用这样的东西覆盖 org.apache.http.impl.client.DefaultClientConnectionReuseStrategy 来完成:

class MyConnectionReuseStrategy extends DefaultClientConnectionReuseStrategy{
    @Override
    public boolean keepAlive(final HttpResponse response, final HttpContext context) {
        final HttpRequest request = (HttpRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST);
        if (request != null) {
            final Header[] contLenHeaders = request.getHeaders(HttpHeaders.CONTENT_LENGTH);
            for(Header h : contLenHeaders){
                if("0".equalsIgnoreCase(h.getValue())){
                    return false;
                }
            }
        }
        return super.keepAlive(response, context);
    }

}

你可以这样设置:

   HttpClients.custom
        .....
        .setConnectionReuseStrategy(new MyConnectionReuseStrategy())
        .build();