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?
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());