web-dev-qa-db-fra.com

Comment analyser le corps de réponse en Java, lorsque la demande HTTP a le statut de retour 401

Je consomme une API JSON RESTful en utilisant RestTemplate et Jackson de Spring. Dans certains cas, nous pouvons recevoir un Status 401 (Non autorisée) réponse avec un corps JSON personnalisé, qui est défini par le fabricant de l'API, et ressemble à ceci:

{
    "code": 123,
    "message": "Reason for the error"
}

Nous devons analyser le corps et utiliser la propriété code dans notre logique métier.

Voici la réponse d'erreur Java objet que nous devons analyser:

public class CustomError {

    @JsonProperty
    private Integer code;
    @JsonProperty
    private String message;

    public Integer getCode() {
       return code;
    }
    public String getMessage() {
        return message;
    }
}

Et un gestionnaire d'erreur personnalisé pour ce faire:

public class CustomErrorHandler extends DefaultResponseErrorHandler {
    private RestTemplate restTemplate;
    private ObjectMapper objectMapper;
    private MappingJacksonHttpMessageConverter messageConverter;


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

    @Override
    public void handleError(final ClientHttpResponse response) throws IOException {

        try {
            CustomError error = 
                (CustomError) messageConverter.read(CustomError.class, response);
            throw new CustomErrorIOException(error, error.getMessage());
        } catch (Exception e) {
            // parsing failed, resort to default behavior
            super.handleError(response);
        }
    }
}

Le gestionnaire d'erreurs échoue avec un HttpMessageNotReadableException dans le bloc try:

"Impossible de lire JSON: impossible de réessayer en raison de l'authentification du serveur, en mode streaming"

Voici comment j'envoie des demandes:

restTemplate.postForObject(url, pojoInstance, responseClass);

Si la même demande est exécutée avec un ancien programme client de repos simple, comme Postman, la réponse JSON attendue est reçue. Donc, je suppose que le problème pourrait être lié à l'implémentation de ClientHttpResponse de Spring d'une manière ou d'une autre ne permettant pas l'accès au corps de la réponse, dans le cas du statut 401.

Est-il vraiment possible d'analyser le corps de réponse?

Mise à jour

D'après ce que j'ai étudié, la classe RestTemplate utilise ClientHttpResponse qui à son tour crée un Sun.net.www.protocol.http.HttpURLConnection qui fournit le flux d'entrée. Il est là, où le flux d'entrée est négligé et un IOException est lancé:

ne peut pas réessayer en raison de l'authentification du serveur, en mode streaming

Ainsi, l'implémentation de HttpURLConnection est à l'origine du problème.

Sera-t-il possible d'éviter ce problème? Peut-être devrions-nous utiliser une implémentation alternative qui n'ignore pas le corps de la réponse en cas de code d'état d'erreur? Pouvez-vous recommander des alternatives?

20
Ivaylo Slavov

Essayez l'approche suivante sans avoir besoin d'un gestionnaire personnalisé. L'idée est d'obtenir la réponse sous forme de chaîne à partir de l'exception HttpStatusCodeException, puis vous pouvez la convertir en votre objet. Pour la conversion, j'ai utilisé l'ObjectMapper de Jackson:

        try {

            restTemplate.postForObject(url, pojoInstance, responseClass);

        } catch (HttpStatusCodeException e) {

            if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {

                String responseString = e.getResponseBodyAsString();

                ObjectMapper mapper = new ObjectMapper();

                CustomError result = mapper.readValue(responseString,
                        CustomError.class);
            }
        }

pdate: L'utilisation d'une usine différente peut également aider car il y a un bug dans celui par défaut lié à votre problème (voir le commentaire ci-dessous):

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
37
Marios