J'utilise webflux Mono (dans Spring boot 5) pour consommer une API externe. Je peux obtenir des données correctement lorsque le code d'état de réponse de l'API est 200, mais lorsque l'API renvoie une erreur, je ne suis pas en mesure de récupérer le message d'erreur de l'API. Le gestionnaire d'erreurs du client Web Spring affiche toujours le message sous la forme
ClientResponse has erroneous status code: 500 Internal Server Error
, mais lorsque j'utilise PostMan, l'API renvoie cette réponse JSON avec le code d'état 500.
{
"error": {
"statusCode": 500,
"name": "Error",
"message":"Failed to add object with ID:900 as the object exists",
"stack":"some long message"
}
}
Ma demande en utilisant WebClient est la suivante
webClient.getWebClient()
.post()
.uri("/api/Card")
.body(BodyInserters.fromObject(cardObject))
.retrieve()
.bodyToMono(String.class)
.doOnSuccess( args -> {
System.out.println(args.toString());
})
.doOnError( e ->{
e.printStackTrace();
System.out.println("Some Error Happend :"+e);
});
Ma question est, comment puis-je accéder à la réponse JSON lorsque l'API renvoie une erreur avec un code d'état de 500?
Regardez .onErrorMap()
, qui vous donne l'exception à regarder. Puisque vous pourriez également avoir besoin du corps () de l'échange () pour regarder, n'utilisez pas la récupération, mais
.exchange().flatMap((ClientResponse) response -> ....);
Si vous souhaitez récupérer les détails de l'erreur:
WebClient webClient = WebClient.builder()
.filter(ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
if (clientResponse.statusCode().isError()) {
return clientResponse.bodyToMono(ErrorDetails.class)
.flatMap(errorDetails -> Mono.error(new CustomClientException(clientResponse.statusCode(), errorDetails)));
}
return Mono.just(clientResponse);
}))
.build();
avec
class CustomClientException extends WebClientException {
private final HttpStatus status;
private final ErrorDetails details;
CustomClientException(HttpStatus status, ErrorDetails details) {
super(status.getReasonPhrase());
this.status = status;
this.details = details;
}
public HttpStatus getStatus() {
return status;
}
public ErrorDetails getDetails() {
return details;
}
}
et avec la classe ErrorDetails
mappant le corps de l'erreur
Variante par demande:
webClient.get()
.exchange()
.map(clientResponse -> {
if (clientResponse.statusCode().isError()) {
return clientResponse.bodyToMono(ErrorDetails.class)
.flatMap(errorDetails -> Mono.error(new CustomClientException(clientResponse.statusCode(), errorDetails)));
}
return clientResponse;
})
Tout comme @Frischling l'a suggéré, j'ai changé ma demande pour qu'elle se présente comme suit
return webClient.getWebClient()
.post()
.uri("/api/Card")
.body(BodyInserters.fromObject(cardObject))
.exchange()
.flatMap(clientResponse -> {
if (clientResponse.statusCode().is5xxServerError()) {
clientResponse.body((clientHttpResponse, context) -> {
return clientHttpResponse.getBody();
});
return clientResponse.bodyToMono(String.class);
}
else
return clientResponse.bodyToMono(String.class);
});
J'ai également noté qu'il existe quelques codes d'état de 1xx à 5xx, ce qui facilitera la gestion des erreurs pour différents cas