问题描述
我正在使用Apache HttpClient 4.5.1向我们的服务器发送一些请求.为了提高性能,我想对所有这些请求重用相同的HttpClient实例.这些请求(大多数)是按顺序发生的,因此不涉及多线程.
I am using Apache HttpClient 4.5.1 to send some requests to our server. To improve performance I'd like to reuse the same HttpClient instance for all those requests. The requests (mostly) happen in sequential order, so there is no multi-threading involved.
不幸的是,某些服务器端点有故障.他们正在返回HTTP 204(无内容),但是响应主体中仍然有一些数据.即使此问题已在最新版本中修复,我们仍将不得不处理旧版本一段时间.此服务器行为导致HTTP客户端在下一个请求挂起"(/超时)(请参阅(有关详细信息).
Unfortunately some of the servers endpoints are faulty. They are returning a HTTP 204 (No content), but some data in the response body anyway. Even though this has been fixed in the latest release, we will have to deal with the older versions for quite a while. This server behaviour causing the HTTP Client to "hang" (/timeout) on the next request (see Every second request using Apache HTTPClient fails for details).
是否有解决此问题的方法?我尝试过了
Is there a way to workaround this on client side? I tried this
HttpEntity entity = response.getEntity();
if (null != entity) {
EntityUtils.consumeQuietly(entity);
}
但是实体似乎为空,因此我无法使用卡在连接套接字中的响应数据.还有另一种方法可以在不丢弃HttpClient实例(及其HTTP连接)的情况下清理套接字吗?
but entity seems to be null, so I cannot consume the response data stuck in connection socket. Is there another way to clean the socket without throwing away the HttpClient instance (and its HTTP connection)?
客户端日志如下:
DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 90000
MainClientExec - Executing request DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1
MainClientExec - Target auth state: UNCHALLENGED
MainClientExec - Proxy auth state: UNCHALLENGED
headers - http-outgoing-0 >> DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1
headers - http-outgoing-0 >> Host: xyz
headers - http-outgoing-0 >> Connection: Keep-Alive
headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)
headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
wire - http-outgoing-0 >> "DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1[\r][\n]"
wire - http-outgoing-0 >> "Host: xyz[\r][\n]"
wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)[\r][\n]"
wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
wire - http-outgoing-0 >> "[\r][\n]"
wire - http-outgoing-0 << "HTTP/1.1 401 Unauthorized[\r][\n]"
wire - http-outgoing-0 << "Date: Mon, 05 Oct 2015 13:30:35 GMT[\r][\n]"
wire - http-outgoing-0 << "Server: Apache/2.2.12 (Linux/SUSE)[\r][\n]"
wire - http-outgoing-0 << "Pragma: No-cache[\r][\n]"
wire - http-outgoing-0 << "Cache-Control: no-cache[\r][\n]"
wire - http-outgoing-0 << "Expires: Thu, 01 Jan 1970 01:00:00 CET[\r][\n]"
wire - http-outgoing-0 << "WWW-Authenticate: Basic realm="ApplicationRealm"[\r][\n]"
wire - http-outgoing-0 << "Content-Length: 958[\r][\n]"
wire - http-outgoing-0 << "Keep-Alive: timeout=15, max=100[\r][\n]"
wire - http-outgoing-0 << "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 << "Content-Type: text/html;charset=utf-8[\r][\n]"
wire - http-outgoing-0 << "[\r][\n]"
headers - http-outgoing-0 << HTTP/1.1 401 Unauthorized
headers - http-outgoing-0 << Date: Mon, 05 Oct 2015 13:30:35 GMT
headers - http-outgoing-0 << Server: Apache/2.2.12 (Linux/SUSE)
headers - http-outgoing-0 << Pragma: No-cache
headers - http-outgoing-0 << Cache-Control: no-cache
headers - http-outgoing-0 << Expires: Thu, 01 Jan 1970 01:00:00 CET
headers - http-outgoing-0 << WWW-Authenticate: Basic realm="ApplicationRealm"
headers - http-outgoing-0 << Content-Length: 958
headers - http-outgoing-0 << Keep-Alive: timeout=15, max=100
headers - http-outgoing-0 << Connection: Keep-Alive
headers - http-outgoing-0 << Content-Type: text/html;charset=utf-8
MainClientExec - Connection can be kept alive for 15000 MILLISECONDS
HttpAuthenticator - Authentication required
HttpAuthenticator - xyz:443 requested authentication
TargetAuthenticationStrategy - Authentication schemes in the order of preference: [Negotiate, Kerberos, NTLM, Digest, Basic]
TargetAuthenticationStrategy - Challenge for Negotiate authentication scheme not available
TargetAuthenticationStrategy - Challenge for Kerberos authentication scheme not available
TargetAuthenticationStrategy - Challenge for NTLM authentication scheme not available
TargetAuthenticationStrategy - Challenge for Digest authentication scheme not available
HttpAuthenticator - Selected authentication options: [BASIC [complete=true]]
wire - http-outgoing-0 << "<html><head><title>JBoss Web/7.0.13.Final - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 401 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>This request requires HTTP authentication ().</u></p><HR size="1" noshade="noshade"><h3>JBoss Web/7.0.13.Final</h3></body></html>"
DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 90000
MainClientExec - Executing request DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1
MainClientExec - Target auth state: CHALLENGED
HttpAuthenticator - Generating response to an authentication challenge using basic scheme
MainClientExec - Proxy auth state: UNCHALLENGED
headers - http-outgoing-0 >> DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1
headers - http-outgoing-0 >> Host: xyz
headers - http-outgoing-0 >> Connection: Keep-Alive
headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)
headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
headers - http-outgoing-0 >> Authorization: Basic dGN1YWRtaW46c3RhcnQ=
wire - http-outgoing-0 >> "DELETE /prod/update-rest/private/deleteGroup/AS123 HTTP/1.1[\r][\n]"
wire - http-outgoing-0 >> "Host: xyz[\r][\n]"
wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)[\r][\n]"
wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
wire - http-outgoing-0 >> "Authorization: Basic dGN1YWRtaW46c3RhcnQ=[\r][\n]"
wire - http-outgoing-0 >> "[\r][\n]"
wire - http-outgoing-0 << "HTTP/1.1 204 No Content[\r][\n]"
wire - http-outgoing-0 << "Date: Mon, 05 Oct 2015 13:30:35 GMT[\r][\n]"
wire - http-outgoing-0 << "Server: Apache/2.2.12 (Linux/SUSE)[\r][\n]"
wire - http-outgoing-0 << "Pragma: No-cache[\r][\n]"
wire - http-outgoing-0 << "Cache-Control: no-cache[\r][\n]"
wire - http-outgoing-0 << "Expires: Thu, 01 Jan 1970 01:00:00 CET[\r][\n]"
wire - http-outgoing-0 << "Content-Length: 22[\r][\n]"
wire - http-outgoing-0 << "Keep-Alive: timeout=15, max=99[\r][\n]"
wire - http-outgoing-0 << "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 << "Content-Type: */*[\r][\n]"
wire - http-outgoing-0 << "[\r][\n]"
headers - http-outgoing-0 << HTTP/1.1 204 No Content
headers - http-outgoing-0 << Date: Mon, 05 Oct 2015 13:30:35 GMT
headers - http-outgoing-0 << Server: Apache/2.2.12 (Linux/SUSE)
headers - http-outgoing-0 << Pragma: No-cache
headers - http-outgoing-0 << Cache-Control: no-cache
headers - http-outgoing-0 << Expires: Thu, 01 Jan 1970 01:00:00 CET
headers - http-outgoing-0 << Content-Length: 22
headers - http-outgoing-0 << Keep-Alive: timeout=15, max=99
headers - http-outgoing-0 << Connection: Keep-Alive
headers - http-outgoing-0 << Content-Type: */*
MainClientExec - Connection can be kept alive for 15000 MILLISECONDS
HttpAuthenticator - Authentication succeeded
TargetAuthenticationStrategy - Caching 'basic' auth scheme for https://xyz:443
PoolingHttpClientConnectionManager - Connection [id: 0][route: {s}->https://xyz:443] can be kept alive for 15.0 seconds
PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {s}->https://xyz:443][total kept alive: 1; route allocated: 1 of 20; total allocated: 1 of 20]
RequestAddCookies - CookieSpec selected: default
RequestAuthCache - Auth cache not set in the context
PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://xyz:443][total kept alive: 1; route allocated: 1 of 20; total allocated: 1 of 20]
PoolingHttpClientConnectionManager - Connection leased: [id: 0][route: {s}->https://xyz:443][total kept alive: 0; route allocated: 1 of 20; total allocated: 1 of 20]
DefaultManagedHttpClientConnection - http-outgoing-0: set socket timeout to 90000
MainClientExec - Executing request DELETE /prod/update-rest/private/deleteGroup/AS678 HTTP/1.1
MainClientExec - Target auth state: UNCHALLENGED
MainClientExec - Proxy auth state: UNCHALLENGED
headers - http-outgoing-0 >> DELETE /prod/update-rest/private/deleteGroup/AS678 HTTP/1.1
headers - http-outgoing-0 >> Host: xyz
headers - http-outgoing-0 >> Connection: Keep-Alive
headers - http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)
headers - http-outgoing-0 >> Accept-Encoding: gzip,deflate
wire - http-outgoing-0 >> "DELETE /prod/update-rest/private/deleteGroup/AS678 HTTP/1.1[\r][\n]"
wire - http-outgoing-0 >> "Host: xyz[\r][\n]"
wire - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.1 (Java/1.7.0_79)[\r][\n]"
wire - http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
wire - http-outgoing-0 >> "[\r][\n]"
wire - http-outgoing-0 << "Group AS123 not found!"
wire - http-outgoing-0 << "HTTP/1.1 401 Unauthorized[\r][\n]"
wire - http-outgoing-0 << "Date: Mon, 05 Oct 2015 13:30:36 GMT[\r][\n]"
wire - http-outgoing-0 << "Server: Apache/2.2.12 (Linux/SUSE)[\r][\n]"
wire - http-outgoing-0 << "Pragma: No-cache[\r][\n]"
wire - http-outgoing-0 << "Cache-Control: no-cache[\r][\n]"
wire - http-outgoing-0 << "Expires: Thu, 01 Jan 1970 01:00:00 CET[\r][\n]"
wire - http-outgoing-0 << "WWW-Authenticate: Basic realm="ApplicationRealm"[\r][\n]"
wire - http-outgoing-0 << "Content-Length: 958[\r][\n]"
wire - http-outgoing-0 << "Keep-Alive: timeout=15, max=98[\r][\n]"
wire - http-outgoing-0 << "Connection: Keep-Alive[\r][\n]"
wire - http-outgoing-0 << "Content-Type: text/html;charset=utf-8[\r][\n]"
wire - http-outgoing-0 << "[\r][\n]"
DefaultHttpResponseParser - Garbage in response: Group AS123 not found!HTTP/1.1 401 Unauthorized
DefaultHttpResponseParser - Garbage in response: Date: Mon, 05 Oct 2015 13:30:36 GMT
DefaultHttpResponseParser - Garbage in response: Server: Apache/2.2.12 (Linux/SUSE)
DefaultHttpResponseParser - Garbage in response: Pragma: No-cache
推荐答案
我设法解决了这个问题:
I managed to work around my problem:
我创建了 HttpRequestExecutor 的子类,重写了 canResponseHaveBody 方法,如下所示:
I created a subclass of HttpRequestExecutor overriding the canResponseHaveBody method like this:
protected boolean canResponseHaveBody(final HttpRequest request,
final HttpResponse response) {
if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
return false;
}
final int status = response.getStatusLine().getStatusCode();
return status >= HttpStatus.SC_OK
// && status != HttpStatus.SC_NO_CONTENT
&& status != HttpStatus.SC_NOT_MODIFIED
&& status != HttpStatus.SC_RESET_CONTENT;
}
使用 HttpClients.custom().setRequestExecutor()注册后,我能够通过 response.getEntity()检索垃圾并将其消耗.
After registering it using HttpClients.custom().setRequestExecutor() I was able to retrive the garbage via response.getEntity() and consume it.
此后,下一个请求就像魅力一样.
Afterwards the next request works like charm.
这篇关于使HttpClient消耗“垃圾";在下一个请求之前的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!