首页 文章

使用webflux处理异常并返回正确的HTTP代码

提问于
浏览
4

我正在使用WebFlux的功能 endpoints . 我使用 onErrorResume 将服务层发送的异常转换为HTTP错误代码:

public Mono<String> serviceReturningMonoError() {
    return Mono.error(new RuntimeException("error"));  
}

public Mono<ServerResponse> handler(ServerRequest request) {
    return serviceReturningMonoError().flatMap(e -> ok().syncBody(e))
                            .onErrorResume( e -> badRequest(e.getMessage()));
}

一旦服务返回Mono,它就能很好地工作 . 如果服务返回Flux,我该怎么办?

public Flux<String> serviceReturningFluxError() {
    return Flux.error(new RuntimeException("error"));  
}

public Mono<ServerResponse> handler(ServerRequest request) {
    ???
}

Edit

我尝试了下面的方法,但不幸的是它不起作用 . Flux.error不由 onErrorResume 处理并传播到框架 . 当在http响应的序列化期间取消装箱异常时,Spring Boot异常管理会捕获它并将其转换为500 .

public Mono<ServerResponse> myHandler(ServerRequest request) {
      return ok().contentType(APPLICATION_JSON).body( serviceReturningFluxError(), String.class)
             .onErrorResume( exception -> badRequest().build());
}

我实际上对这个行为感到惊讶,那是一个bug吗?

2 回答

  • 1

    您的第一个示例使用 Mono (即最多一个值),因此它与 Mono<ServerResponse> 一起使用 - 该值将在内存中异步解析,并且根据结果我们将返回不同的响应或手动处理业务异常 .

    Flux (即0..N值)的情况下,在任何给定时间都可能发生错误 .

    在这种情况下,您可以使用 collectList 运算符将 Flux<String> 变为 Mono<List<String>> ,并发出一个大警告:所有元素都将缓冲在内存中 . 如果您的控制器/客户端依赖于流数据,那么数据流非常重要,这不是最佳选择 .

    我为这个问题提供了更好的解决方案,原因如下:由于错误可能在 Flux 期间的任何时间发生,因此无法保证我们可以更改HTTP状态和响应:事情可能已经在网络上刷新了 . 使用Spring MVC并返回 InputStreamResource 时已经是这种情况了 .

    Spring Boot错误处理功能尝试编写错误页面并更改HTTP状态(请参阅 ErrorWebExceptionHandler 并实现类),但如果响应已提交,它将记录错误信息并让您知道HTTP状态可能是错误的 .

  • 2

    我找到另一种方法来解决这个问题,在 body 方法中捕获异常并将其映射到 ResponseStatusException

    public Mono<ServerResponse> myHandler(ServerRequest request) {
        return ok().contentType(MediaType.APPLICATION_JSON)
                .body( serviceReturningFluxError()
                        .onErrorMap(RuntimeException.class, e -> new ResponseStatusException( BAD_REQUEST, e.getMessage())), String.class);
    }
    

    使用这种方法,Spring可以正确处理响应并返回预期的HTTP错误代码 .

相关问题