简体   繁体   中英

Spring Reactive Web - Exceptions are always wrapped in 500

With a very simple project, error handling is unclear.

public class WebfluxApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebfluxApplication.class, args);
    }
}
public class EndpointRouter
{

@Bean
public WebClient webClient() {
    return WebClient.builder().build();
}

@Bean
public RouterFunction<ServerResponse> goodRoute(Handler handler, ConfigProperties configProperties) {
    log.info(configProperties.toString());
    return
            RouterFunctions.route(RequestPredicates.GET("/api/v1/integration/ok"),
                    handler::goodEndpoint)
    .and(
            RouterFunctions.route(RequestPredicates.GET("/api/v1/integration/notfound") {
                    handler::badEndpoint));
}
public Mono<ServerResponse> goodEndpoint(ServerRequest r) {
    return ServerResponse.ok().build();
}

public Mono<ServerResponse> badEndpoint(ServerRequest r) {
    var result = service.badEndpoint();
    return ServerResponse
            .ok()
            .body(result, String.class);
}
public class Service
{
private final WebClient webClient;
private final ConfigProperties configProperties;

public Service(WebClient webClient, ConfigProperties configurationProperties) {
    this.webClient = webClient;
    this.configProperties = configurationProperties;
}

public Mono<String> badEndpoint() {
    return webClient
            .get()
            .uri(configProperties.getNotfound())
            .retrieve()
            .onStatus(HttpStatus::is4xxClientError, clientResponse -> {
                if(clientResponse.statusCode().equals(HttpStatus.NOT_FOUND)){
                    return Mono.error(new HttpClientErrorException(HttpStatus.NOT_FOUND,
                            "Entity not found."));
                } else {
                    return Mono.error(new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
                }
            })
            .bodyToMono(String.class);
}

From reading the docs, I shouldn't need to set up a Global error handler for the entire project, I should be able to handle the 404, and return a 404 back to the original caller.

This is the output

   2020-08-29 16:52:46.301 ERROR 25020 --- [ctor-http-nio-4] a.w.r.e.AbstractErrorWebExceptionHandler : [b339763e-1]  500 Server Error for HTTP GET "/api/v1/integration/notfound"

org.springframework.web.client.HttpClientErrorException: 404 Entity not found.
    at com.stevenpg.restperformance.webflux.Service.lambda$badEndpoint$0(Service.java:30) ~[main/:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ 404 from GET https://httpbin.org/status/404 [DefaultWebClient]
    |_ checkpoint ⇢ Handler com.stevenpg.restperformance.webflux.EndpointRouter$$Lambda$445/0x00000008003ae040@7799b58 [DispatcherHandler]
    |_ checkpoint ⇢ HTTP GET "/api/v1/integration/notfound" [ExceptionHandlingWebHandler]

I've also tried using onErrorResume on my Mono from the service, but it never works correct and requires a return of Mono rather than Mono.

The documentation and Stack Overflow don't have many/any examples of making a WebClient call inside a RouterFunction and handling different types of responses.

Just adding onErrorResume solves your problem. Otherwise error is handled in AbstractErrorWebExceptionHandler.

 return webClient
        .get()
        .uri(configProperties.getNotfound())
        .retrieve()
        .onStatus(HttpStatus::is4xxClientError, clientResponse -> {
            if(clientResponse.statusCode().equals(HttpStatus.NOT_FOUND)){
                return Mono.error(new HttpClientErrorException(HttpStatus.NOT_FOUND,
                        "Entity not found."));
            } else {
                return Mono.error(new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
            }
        })
        .bodyToMono(String.class)
        .onErrorResume( e -> Mono.just(e.getMessage()) );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM