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 ?

135voto

oleg Points 7016

Il est fort probable que les connexions persistantes qui sont maintenues en vie par le gestionnaire de connexions deviennent périmées. En d'autres termes, le serveur cible ferme la connexion de son côté sans que HttpClient puisse réagir à cet événement, alors que la connexion est inactive, ce qui rend la connexion à moitié fermée ou "périmée". En général, ce n'est pas un problème. HttpClient utilise plusieurs techniques pour vérifier la validité de la connexion lors de sa location à partir du pool. Même si la vérification des connexions périmées est désactivée et qu'une connexion périmée est utilisée pour transmettre un message de demande, l'exécution de la demande échoue généralement lors de l'opération d'écriture avec une SocketException et est automatiquement relancée. Cependant, dans certaines circonstances, l'opération d'écriture peut se terminer sans exception et l'opération de lecture suivante renvoie -1 (end of stream). Dans ce cas, HttpClient n'a pas d'autre choix que de supposer que la requête a réussi mais que le serveur n'a pas répondu, probablement en raison d'une erreur inattendue du côté du serveur.

La façon la plus simple de remédier à cette situation est d'expulser du pool les connexions expirées et celles qui sont restées inactives pendant plus d'une minute, par exemple, après une période d'inactivité. Pour plus de détails, veuillez consulter cette section du tutoriel HttpClient .

22voto

Jehy Points 311

La réponse acceptée est correcte mais manque de solution. Pour éviter cette erreur, vous pouvez ajouter setHttpRequestRetryHandler (ou setRetryHandler pour les composants apache 4.4) pour votre client HTTP comme dans cette réponse .

7voto

Brian Agnew Points 143181

HttpClient 4.4 a souffert d'un bogue dans ce domaine concernant la validation des connexions éventuellement périmées avant de retourner au demandeur. Il s'agit de n'a pas valider si une connexion était périmée, ce qui entraîne immédiatement une NoHttpResponseException .

Ce problème a été résolu dans HttpClient 4.4.1. Voir ce JIRA et le notes de mise à jour

5voto

Grzesiek D. Points 656

Bien que la réponse acceptée soit correcte, IMHO est juste une solution de rechange.

Pour être clair : il est tout à fait normal qu'une connexion persistante devienne périmée. Mais malheureusement, c'est très mauvais quand la bibliothèque client HTTP ne peut pas le gérer correctement.

Étant donné que ce comportement défectueux dans Apache HttpClient n'a pas été corrigé pendant de nombreuses années, je préfère nettement passer à une bibliothèque qui peut facilement se remettre d'un problème de connexion périmée, par exemple OkHttp.

Pourquoi ?

  1. OkHttp regroupe les connexions http par défaut.
  2. Il se remet gracieusement des situations où la connexion http devient périmée et où la requête ne peut être relancée parce qu'elle n'est pas idempotente (par exemple POST). Je ne peux pas dire la même chose de Apache HttpClient (mentionné NoHttpResponseException ).
  3. Prend en charge HTTP/2.0 dès les premières ébauches et les versions bêta.

Quand je suis passé à OkHttp, mes problèmes de NoHttpResponseException a disparu pour toujours.

5voto

Anti-g Points 1

Solution : changer la ReuseStrategy pour ne jamais

Comme ce problème est très complexe et qu'il y a tellement de facteurs différents qui peuvent échouer, j'ai été heureux de trouver cette solution dans un autre article : Comment résoudre org.apache.http.NoHttpResponseException ?

Ne réutilisez jamais les connexions : configure dans org.apache.http.impl.client.AbstractHttpClient :

httpClient.setReuseStrategy(new NoConnectionReuseStrategy());

La même chose peut être configurée sur un constructeur org.apache.http.impl.client.HttpClientBuilder :

builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());

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