94 votes

Apache HttpClient Interim Error : NoHttpResponseException

J'ai un webservice qui accepte une méthode POST avec XML. Il fonctionne bien puis, à un moment donné, il ne parvient pas à communiquer avec le serveur en lançant une IOException avec le message suivant The target server failed to respond . Les appels suivants fonctionnent bien.

Cela se produit surtout lorsque je fais quelques appels et que je laisse mon application inactive pendant 10 à 15 minutes. Le premier appel que je fais ensuite renvoie cette erreur.

J'ai essayé plusieurs choses...

J'ai configuré le gestionnaire de réessai comme suit

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);

mais cette nouvelle tentative n'a jamais été appelée. (oui, j'utilise la bonne clause instanceof). Pendant le débogage, cette classe n'a jamais été appelée.

J'ai même essayé de mettre en place HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); mais sans utilité. Quelqu'un peut-il me suggérer ce que je peux faire maintenant ?

IMPORTANT Outre le fait de comprendre pourquoi je reçois l'exception, l'une des préoccupations importantes que j'ai est de savoir pourquoi le retryhandler ne fonctionne pas ici ?

4voto

Berthier Lemieux Points 1093

De nos jours, la plupart des connexions HTTP sont considérées comme persistantes, sauf déclaration contraire . Toutefois, pour économiser les ressources du serveur, la connexion est rarement maintenue ouverte indéfiniment, le délai de connexion par défaut de nombreux serveurs est plutôt court, par exemple 5 secondes pour Apache httpd 2.2 et plus.

Le site org.apache.http.NoHttpResponseException L'erreur provient très probablement d'une connexion persistante qui a été fermée par le serveur.

Il est possible de définir la durée maximale de maintien des connexions inutilisées ouvertes dans le pool de clients Apache Http, en millisecondes.

Avec Spring Boot, une façon d'y parvenir :

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();
}

2voto

Amalgovinus Points 889

Cela peut se produire si disableContentCompression() est défini sur un gestionnaire de pooling attribué à votre HttpClient, et le serveur cible essaie d'utiliser la compression gzip.

1voto

Salvatore Napoli Points 380

Même problème pour moi sur le client apache http 4.5.5 ajout d'un en-tête par défaut

Connexion : close

résoudre le problème

0voto

Alok Sahoo Points 1

Utilisez PoolingHttpClientConnectionManager au lieu de BasicHttpClientConnectionManager

BasicHttpClientConnectionManager s'efforcera de réutiliser la connexion pour les demandes ultérieures avec la même route. Cependant, il fermera la connexion existante et la rouvrira pour la route donnée.

-2voto

Chandrahasan Points 728

J'ai rencontré le même problème, je l'ai résolu en ajoutant "connection : close" comme extension,

Étape 1 : créer une nouvelle classe 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";
  }
}

Etape 2 : définir la classe d'extension dans wireMockServer comme ci-dessous,

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X