164 votes

Traitement des exceptions de Spring Resttemplate

Voici le bout de code ; en fait, j'essaie de propager l'exception lorsque le code d'erreur est différent de 200.

ResponseEntity<Object> response = restTemplate.exchange(url.toString().replace("{version}", version),
                    HttpMethod.POST, entity, Object.class);
            if(response.getStatusCode().value()!= 200){
                logger.debug("Encountered Error while Calling API");
                throw new ApplicationException();
            }

Cependant, dans le cas d'une réponse 500 du serveur, je reçois l'exception suivante

org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]

Dois-je vraiment envelopper le reste de la méthode d'échange de modèles dans un try ? À quoi serviraient alors les codes ?

0 votes

Veuillez partager le code de ApplicationException().

161voto

carcaret Points 1749

Vous voulez créer une classe qui implémente ResponseErrorHandler puis utilisez une instance de celui-ci pour définir la gestion des erreurs de votre modèle de repos :

public class MyErrorHandler implements ResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }

  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
     ...
  }
}

[...]

public static void main(String args[]) {
  RestTemplate restTemplate = new RestTemplate();
  restTemplate.setErrorHandler(new MyErrorHandler());
}

De plus, Spring dispose de la classe DefaultResponseErrorHandler que vous pouvez étendre au lieu d'implémenter l'interface, au cas où vous ne voudriez que remplacer l'interface handleError méthode.

public class MyErrorHandler extends DefaultResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }
}

Jetez un coup d'œil à son code source pour avoir une idée de la façon dont Spring gère les erreurs HTTP.

9 votes

J'ai une instance de RestTemplate que je réutilise pour différents appels. J'ai besoin de traiter les erreurs de différents appels différemment - apparemment il n'y a aucun moyen de le faire avec un gestionnaire global - je dois fournir un gestionnaire par demande.

6 votes

Avec ce gestionnaire d'erreur, j'obtiens toujours un ResourceAccessException parce que RestTemplate.doExecute attrape IOException et lance un ResourceAccessException . Qu'est-ce que je fais de mal ?

0 votes

J'ai pu résoudre ce problème en étendant DefaultResponseErrorHandler.

84voto

austin cherlo Points 81

Spring traite intelligemment les codes d'erreur http comme des exceptions, et suppose que votre code de gestion des exceptions dispose du contexte pour traiter l'erreur. Pour que l'échange fonctionne comme vous l'attendez, faites ceci :

    try {
        return restTemplate.exchange(url, httpMethod, httpEntity, String.class);
    } catch(HttpStatusCodeException e) {
        return ResponseEntity.status(e.getRawStatusCode()).headers(e.getResponseHeaders())
                .body(e.getResponseBodyAsString());
    }

Cela renverra tous les résultats attendus de la réponse.

2 votes

Vous devez utiliser un HttpClient différent du SDK par défaut, pour obtenir le corps de la réponse pour les erreurs.

4 votes

C'est utile, merci, mais je ne suis pas d'accord pour dire que supposer des choses est une chose intelligente à faire.

4 votes

"intelligemment" -- citation nécessaire

69voto

mekazu Points 986

Vous devriez attraper un HttpStatusCodeException exception :

try {
    restTemplate.exchange(...);
} catch (HttpStatusCodeException exception) {
    int statusCode = exception.getStatusCode().value();
    ...
}

43 votes

La réponse devrait toujours être accompagnée d'un code d'état approprié, sinon à quoi servent les codes ?

5 votes

Je ne suis pas sûr de comprendre l'objection de @vaibhav : attraper HttpStatusCodeException n'est pas pour un mauvais code, mais parce que dans de nombreux cas une exception est toujours levée et donc votre if(code==value) ne peut jamais être exécuté.

3 votes

Les exceptions sont très coûteuses en Java. Elles sont acceptables pour les causes occasionnelles et inattendues (d'où leur nom), mais au-delà, vous devriez plutôt chercher d'autres solutions.

36voto

Investigator Points 119

Une autre solution est celle décrite ici à la fin de ce post par "enlian" : http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

try{
     restTemplate.exchange(...)
} catch(HttpStatusCodeException e){
     String errorpayload = e.getResponseBodyAsString();
     //do whatever you want
} catch(RestClientException e){
     //no response payload, tell the user sth else 
}

4 votes

Vous devez utiliser un HttpClient différent de celui du SDK par défaut, pour obtenir le corps de la réponse en cas d'erreur (par exemple apache commons HttpClient)

4voto

Hannes Points 654

Si vous utilisez le mécanisme de pooling (http client factory) ou d'équilibrage de charge (eureka) avec votre RestTemplate vous n'aurez pas le luxe de créer une new RestTemplate par classe. Si vous appelez plus d'un service, vous ne pouvez pas utiliser setErrorHandler car elle serait utilisée globalement pour toutes vos demandes.

Dans ce cas, la capture de la HttpStatusCodeException semble être la meilleure option.

La seule autre option que vous avez est de définir de multiples RestTemplate en utilisant l'option @Qualifier annotation.

En outre - mais c'est mon goût personnel - j'aime que mes traitements d'erreurs soient étroitement liés à mes appels.

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