Webflux Mono(Spring boot 5)を使用して外部APIを使用しています。 API応答ステータスコードが200の場合、データをうまく取得できますが、APIがエラーを返した場合、APIからエラーメッセージを取得できません。 Spring webclientエラーハンドラは常にメッセージを次のように表示します
ClientResponse has erroneous status code: 500 Internal Server Error
が、PostManを使用すると、APIはこのJSON応答をステータスコード500で返します。
{
"error": {
"statusCode": 500,
"name": "Error",
"message":"Failed to add object with ID:900 as the object exists",
"stack":"some long message"
}
}
WebClientを使用した私のリクエストは次のとおりです
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);
});
私の質問は、APIがステータスコード500のエラーを返したときにJSON応答にアクセスするにはどうすればよいですか?
.onErrorMap()
を見てください。これは、見るべき例外を与えてくれます。調べるにはexchange()のbody()も必要になる可能性があるため、retrieveを使用しないでください。ただし、
.exchange().flatMap((ClientResponse) response -> ....);
エラーの詳細を取得する場合:
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();
と
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;
}
}
エラー本体をマッピングするErrorDetails
クラスを使用
リクエストごとのバリアント:
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;
})
@Frischlingが示唆したように、リクエストを次のように変更しました
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);
});
また、1xxから5xxのステータスコードがいくつかあることに注意しました。これにより、さまざまなケースでエラー処理が容易になります。