I'm developing some reactive microservices using Spring Boot 2 and Spring 5 with WebFlux reactive starter.
I'm facing the following problem: I want to handle all HTTP Statuses that I receive from calling another REST Services and throws an exception when I receive some bad HTTP Status. For example, when I call an endpoint and I receive an 404 HTTP Status, I want to throw an exception and that exception to be handled in some ExceptionHandler class, just like the way it was in Spring 4 with @ControllerAdvice
.
What is the right way to do this? Hope to receive some good suggestions.
This can be addressed in two independent parts.
When using WebClient
, you can receive HTTP 404 responses from remote services. By default, all 4xx
and 5xx
client responses will be turned into WebClientResponseException
. So you can directly handle those exceptions in your WebFlux app.
If you'd like to turn only 404 responses into custom exceptions, you can do the following:
WebClient webClient = //...
webClient.get().uri("/persons/1")
.retrieve()
.onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
clientResponse -> Mono.error(new MyCustomException()))
.bodyToMono(...);
This is obviously done on a per client call basis.
You can achieve the same in a more reusable way with an ExchangeFilterFunction
that you can set once and for all on a WebClient
instance like this:
WebClient.builder().filter(myExchangeFilterFunction)...
With Spring WebFlux with annotations, you can handle exceptions with methods annotated with @ExceptionHandler
(see Spring Framework reference documentation).
Note: using a WebExceptionHandler
is possible, but it's quite low level as you'll have no high-level support there: you'll need to manually write the response with buffers without any support for serialization.
I think what you are looking for is WebFluxResponseStatusExceptionHandler
the check this for reference.
In the WebHandler API, a WebExceptionHandler can be used to to handle exceptions from the chain of WebFilter's and the target WebHandler. When using the WebFlux Config, registering a WebExceptionHandler is as simple as declaring it as a Spring bean, and optionally expressing precedence via @Order on the bean declaration or by implementing Ordered.
This example may help, have not tried it myself.
@Component
@Order(-2)
class RestWebExceptionHandler implements WebExceptionHandler{
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (ex instanceof PostNotFoundException) {
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
// marks the response as complete and forbids writing to it
return exchange.getResponse().setComplete();
}
return Mono.error(ex);
}
}
class PostNotFoundException extends RuntimeException {
PostNotFoundException(String id) {
super("Post:" + id + " is not found.");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With