web-dev-qa-db-fra.com

Erreur temporaire Apache HttpClient: NoHttpResponseException

J'ai un service Web qui accepte une méthode POST avec XML. Cela fonctionne très bien, mais à une occasion quelconque, il ne parvient pas à communiquer avec le serveur qui renvoie une exception IOException avec le message The target server failed to respond. Les appels suivants fonctionnent bien.

Cela arrive surtout lorsque je passe des appels et que je laisse ensuite mon application inactive pendant 10 à 15 minutes. le premier appel que je fais après renvoie cette erreur.

J'ai essayé deux ou trois choses ...

J'ai configuré le gestionnaire de nouvelle tentative comme

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 right instanceof clause). Pendant le débogage, cette classe n’est jamais appelée.

J'ai même essayé de configurer HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); mais je ne l'utilisais pas. Quelqu'un peut-il suggérer ce que je peux faire maintenant?

IMPORTANT En plus de comprendre pourquoi je reçois une exception, l'une de mes préoccupations importantes est de savoir pourquoi le retainhandler ne travaille-t-il pas ici?

62
Em Ae

Le plus souvent, les connexions persistantes maintenues en vie par le gestionnaire de connexions deviennent obsolètes. C'est-à-dire que le serveur cible ferme la connexion à son extrémité sans que HttpClient puisse réagir à cet événement pendant que la connexion est inactive, ce qui rend la connexion à moitié fermée ou "obsolète". Ce n'est généralement pas un problème. HttpClient utilise plusieurs techniques pour vérifier la validité de la connexion lors de sa location du pool. Même si le contrôle de connexion obsolète est désactivé et qu'une connexion obsolète est utilisée pour transmettre un message de requête, l'exécution de la requête échoue généralement lors de l'opération d'écriture avec SocketException et est automatiquement réessayée. Toutefois, dans certaines circonstances, l'opération d'écriture peut se terminer sans exception et l'opération de lecture suivante renvoie -1 (fin du flux). Dans ce cas, HttpClient n'a pas d'autre choix que de supposer que la demande a abouti, mais le serveur n'a pas répondu probablement en raison d'une erreur inattendue du côté du serveur.

Le moyen le plus simple de remédier à la situation consiste à expulser les connexions expirées et les connexions inactives depuis plus d'une minute, par exemple, à une minute de la piscine après une période d'inactivité. Pour plus de détails, veuillez consulter cette section du didacticiel HttpClient .

96
ok2c

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

15
Jehy

HttpClient 4.4 souffrait d'un bogue dans ce domaine lié à la validation de connexions éventuellement obsolètes avant de retourner au demandeur. n'a pas validé si une connexion était périmée, ce qui entraîne alors un NoHttpResponseException immédiat.

Ce problème a été résolu dans HttpClient 4.4.1. Voir this JIRA et le notes de version

6
Brian Agnew

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

Le org.Apache.http.NoHttpResponseException _ erreur provient probablement d'une connexion persistante qui a été fermée par le serveur.

Il est possible de définir le délai maximal de maintien des connexions inutilisées dans le pool de clients Apache Http, en millisecondes.

Avec Spring Boot, un moyen 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();
}
3
Berthier Lemieux

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

1
Amalgovinus

Bien que la réponse acceptée soit correcte, mais IMHO n’est qu’une solution de contournement.

Pour être clair: c’est une situation parfaitement normale qu’une connexion persistante devienne obsolète. Mais malheureusement, il est très grave que la bibliothèque client HTTP ne puisse pas le gérer correctement.

Étant donné que ce comportement défectueux dans Apache HttpClient n’était pas résolu depuis de nombreuses années, je préférerais définitivement basculer vers une bibliothèque qui puisse facilement résoudre un problème de connexion obsolète, par exemple. OkHttp.

Pourquoi?

  1. OkHttp regroupe les connexions http par défaut.
  2. Il récupère gracieusement à partir de situations où la connexion http devient obsolète et que la demande ne peut pas être réessayée car elle n'est pas idempotente (par exemple, POST). Je ne peux pas le dire à propos d'Apache HttpClient (mentionné NoHttpResponseException).
  3. Prend en charge HTTP/2.0 à partir des versions préliminaires et bêta.

Lorsque je suis passé à OkHttp, mes problèmes avec NoHttpResponseException ont disparu pour toujours.

1
G. Demecki

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

Connexion: fermer

résoudre le problème

1
Salvatore Napoli