web-dev-qa-db-fra.com

java.net.HttpRetryException: impossible de réessayer en raison de l'authentification du serveur, en mode diffusion

Nous avons deux parties dans notre application:
Server - fournit les services REST
Client - consommez-les via Spring restTemplate

En plus du statut HTTP, notre serveur renvoie un corps HTTP avec JSON décrivant l'erreur en détail . J'ai donc ajouté un gestionnaire d'erreur personnalisé à restTemplate pour traiter certaines erreurs codées comme des erreurs - cela aide à bien analyser le corps HTTP. .

Mais je reçois une exception via l'analyse du corps HTTP dans le cas d'un HTTP/1.1 401 non autorisé . Tous les autres codes d'erreur sont gérés correctement (400, 402, etc.) Nous utilisons une logique de serveur en clair qui envoie une réponse HTTP en cas d'erreur, pas de règles spéciales pour les différents types d'erreur:

writeErrorToResponse(int status, String errMsg, HttpServletResponse resp) throws IOException {
        response.setStatus(status);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String message = String.format("{\"error\":\"%s\"}", StringUtils.escapeJson(errMsg));
        resp.getWriter().println(message);
    }

Mais sur le client uniquement, HTTP/1.1 401 lève une exception - "Java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode"

J'ai fait du débogage et je vois que la cause du problème est du code dans SimpleClientHttpResponse:

HttpURLConnection.getInputStream ()

Le traçage avec Fiddler a les réponses suivantes: Le message est correctement analysé sur le client:

HTTP/1.1 402 Payment Required
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Connection: Close
Date: Sat, 25 May 2013 10:10:44 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

Et message qui fait exception:

HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Date: Sat, 25 May 2013 11:00:21 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

Quelle pourrait être la cause de Java.net.HttpRetryException dans cette situation?

En outre : Il y a quelques temps, ce mécanisme fonctionnait bien. Mais depuis que nous avons changé beaucoup de code dans l'application.

21
Oleksandr_DJ

J'ai rencontré le même problème lorsque vous utilisez SimpleClientHttpRequestFactory . Résolu en mettant

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;

Le problème est dû à la fragmentation et au mécanisme de relance ultérieure en cas d'authentification.

Vous pouvez également désactiver des morceaux à l'aide de HttpClientPolicy

19
Harshad Ranganathan

Je pense que le fait de passer une HttpComponentsClientHttpRequestFactory configurée à votre RestTemplate aiderait . Ici , vous pourriez trouver la solution pour le faire.

La raison pour laquelle j'ai utilisé cette solution de développement était de gérer les messages de réponse dans le corps des réponses d'erreur HTTP telles que 401, 404, etc., et de laisser l'application être déployée dans un environnement côté serveur réel.

8
Youness

Ce problème est signalé dans Spring Framework.

Référence: https://jira.spring.io/browse/SPR-9367

Copier depuis la référence: Il est très difficile (impossible) de gérer une réponse 401 dans RestTemplate avec les paramètres par défaut. En fait, c'est possible, mais vous devez fournir un gestionnaire d'erreurs et une fabrique de requêtes. Le gestionnaire d'erreurs était évident, mais le problème est que la fabrique de requêtes par défaut utilise Java.net, ce qui peut générer une exception HttpRetryException lorsque vous essayez d'examiner le code d'état de la réponse (bien qu'il soit évidemment disponible). La solution consiste à utiliser HttpComponentsClientHttpRequestFactory. Par exemple.

template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
template.setErrorHandler(new DefaultResponseErrorHandler() {
    public boolean hasError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = response.getStatusCode();
        return statusCode.series() == HttpStatus.Series.SERVER_ERROR;
    }
});

HttpComponentsClientHttpRequestFactory requiert une dépendance inférieure à. Ajoutez la dépendance ci-dessous dans votre fichier POM:

<dependency>
            <groupId>org.Apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
</dependency>
1
Hemanth