如何在apache http客户端中忽略零内容长度头

时间:2016-04-08 15:09:10

标签: android apache-httpclient-4.x android-networking content-length

服务器响应正文是" []"并且Content-Length = 0.当客户端试图读取提到的响应体时,它总是一次得到" -1"。此外,如果我拦截服务器响应并将内容长度更改为" 2" - 一切正常。我可以得出结论,当Content-Length = 0时,apache http客户端返回-1,但实际上响应体不为空。我正在寻找一种解决方法,即使Content-length不正确也能读取响应正文,即我可以设置http客户端忽略Content-length头值吗?我没有机会修改服务器,出于某些原因我不能使用HttpUrlConnection代替apache客户端。请提出任何建议。

1 个答案:

答案 0 :(得分:1)

错误Content-length的问题是HttpClient不知道响应何时结束,这也会在Keep-Alive连接的情况下中断此连接的下一个请求。 最简单的选择是扩展org.apache.http.impl.entity.LaxContentLengthStrategy并使其在标题中返回内容长度为“2”时为“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中设置哪个可能有点棘手: 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(); 

因此,如果您实际上不需要带有“[]”的正文,则可以指示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();