问题
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.
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);
}
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)?
The client log looks like this:
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
回答1:
I managed to work around my problem:
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;
}
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.
来源:https://stackoverflow.com/questions/32943192/make-httpclient-consume-garbage-before-next-request