Apache HttpClient Interim Error: NoHttpResponseException

JavaHttpclient

Java Problem Overview


I have a webservice which is accepting a POST method with XML. It is working fine then at some random occasion, it fails to communicate to the server throwing IOException with message The target server failed to respond. The subsequent calls work fine.

It happens mostly, when i make some calls and then leave my application idle for like 10-15 min. the first call which I make after that returns this error.

I tried couple of things ...

I setup the retry handler like

HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
			
			public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) {
				if (retryCount >= 3){
					Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block");
					return false;
				}
				if (e instanceof org.apache.http.NoHttpResponseException){
					Logger.warn(CALLER, "No response from server on "+retryCount+" call");
					return true;
				}
				return false;
			}
		};
		
		httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);

but this retry never got called. (yes I am using right instanceof clause). While debugging this class never being called.

I even tried setting up HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); but no use. Can someone suggest what I can do now?

IMPORTANT Besides figuring out why I am getting the exception, one of the important concerns I have is why isn't the retryhandler working here?

Java Solutions


Solution 1 - Java

Most likely persistent connections that are kept alive by the connection manager become stale. That is, the target server shuts down the connection on its end without HttpClient being able to react to that event, while the connection is being idle, thus rendering the connection half-closed or 'stale'. Usually this is not a problem. HttpClient employs several techniques to verify connection validity upon its lease from the pool. Even if the stale connection check is disabled and a stale connection is used to transmit a request message the request execution usually fails in the write operation with SocketException and gets automatically retried. However under some circumstances the write operation can terminate without an exception and the subsequent read operation returns -1 (end of stream). In this case HttpClient has no other choice but to assume the request succeeded but the server failed to respond most likely due to an unexpected error on the server side.

The simplest way to remedy the situation is to evict expired connections and connections that have been idle longer than, say, 1 minute from the pool after a period of inactivity. For details please see this section of the HttpClient tutorial.

Solution 2 - Java

Accepted answer is right but lacks solution. To avoid this error, you can add setHttpRequestRetryHandler (or setRetryHandler for apache components 4.4) for your HTTP client like in this answer.

Solution 3 - Java

HttpClient 4.4 suffered from a bug in this area relating to validating possibly stale connections before returning to the requestor. It didn't validate whether a connection was stale, and this then results in an immediate NoHttpResponseException.

This issue was resolved in HttpClient 4.4.1. See this JIRA and the release notes

Solution 4 - Java

Nowadays, most HTTP connections are considered persistent unless declared otherwise. However, to save server ressources the connection is rarely kept open forever, the default connection timeout for many servers is rather short, for example 5 seconds for the Apache httpd 2.2 and above.

The org.apache.http.NoHttpResponseException error comes most likely from one persistent connection that was closed by the server.

It's possible to set the maximum time to keep unused connections open in the Apache Http client pool, in milliseconds.

With Spring Boot, one way to achieve this:

public class RestTemplateCustomizers {
    static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer {

        @Override
        public void customize(RestTemplate restTemplate) {
            HttpClient httpClient = HttpClientBuilder
                .create()
                .setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS)
                .build();

            restTemplate.setRequestFactory(
                new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    }
}

// In your service that uses a RestTemplate
public MyRestService(RestTemplateBuilder builder ) {
    restTemplate = builder
         .customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer())
         .build();
}

Solution 5 - Java

Although accepted answer is right, but IMHO is just a workaround.

To be clear: it's a perfectly normal situation that a persistent connection may become stale. But unfortunately it's very bad when the HTTP client library cannot handle it properly.

Since this faulty behavior in Apache HttpClient was not fixed for many years, I definitely would prefer to switch to a library that can easily recover from a stale connection problem, e.g. OkHttp.

Why?

  1. OkHttp pools http connections by default.
  2. It gracefully recovers from situations when http connection becomes stale and request cannot be retried due to being not idempotent (e.g. POST). I cannot say it about Apache HttpClient (mentioned NoHttpResponseException).
  3. Supports HTTP/2.0 from early drafts and beta versions.

When I switched to OkHttp, my problems with NoHttpResponseException disappeared forever.

Solution 6 - Java

Solution: change the ReuseStrategy to never

Since this problem is very complex and there are so many different factors which can fail I was happy to find this solution in another post: https://stackoverflow.com/questions/29006222/how-to-solve-org-apache-http-nohttpresponseexception#

Never reuse connections: configure in org.apache.http.impl.client.AbstractHttpClient:

httpClient.setReuseStrategy(new NoConnectionReuseStrategy());

The same can be configured on a org.apache.http.impl.client.HttpClientBuilder builder:

builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());

Solution 7 - Java

This can happen if disableContentCompression() is set on a pooling manager assigned to your HttpClient, and the target server is trying to use gzip compression.

Solution 8 - Java

Same problem for me on apache http client 4.5.5 adding default header

Connection: close

resolve the problem

Solution 9 - Java

Use PoolingHttpClientConnectionManager instead of BasicHttpClientConnectionManager

BasicHttpClientConnectionManager will make an effort to reuse the connection for subsequent requests with the same route. It will, however, close the existing connection and re-open it for the given route.

Solution 10 - Java

I have faced same issue, I resolved by adding "connection: close" as extention,

Step 1: create a new class ConnectionCloseExtension

import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.http.HttpHeader;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;

public class ConnectionCloseExtension extends ResponseTransformer {
  @Override
  public Response transform(Request request, Response response, FileSource files, Parameters parameters) {
    return Response.Builder
        .like(response)
        .headers(HttpHeaders.copyOf(response.getHeaders())
            .plus(new HttpHeader("Connection", "Close")))
        .build();
  }

  @Override
  public String getName() {
    return "ConnectionCloseExtension";
  }
}

Step 2: set extension class in wireMockServer like below,

final WireMockServer wireMockServer = new WireMockServer(options()
                .extensions(ConnectionCloseExtension.class)
                .port(httpPort));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEm AeView Question on Stackoverflow
Solution 1 - Javaok2cView Answer on Stackoverflow
Solution 2 - JavaJehyView Answer on Stackoverflow
Solution 3 - JavaBrian AgnewView Answer on Stackoverflow
Solution 4 - JavaBerthier LemieuxView Answer on Stackoverflow
Solution 5 - JavaG. DemeckiView Answer on Stackoverflow
Solution 6 - JavaAnti-gView Answer on Stackoverflow
Solution 7 - JavaAmalgovinusView Answer on Stackoverflow
Solution 8 - JavaSalvatore NapoliView Answer on Stackoverflow
Solution 9 - JavaAlok SahooView Answer on Stackoverflow
Solution 10 - JavaChandrahasanView Answer on Stackoverflow