我正在使用WebFlux的功能端点。我使用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) {
???
}
编辑
我尝试了下面的方法,但不幸的是它不起作用。 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吗?
你的第一个样本是使用Mono
(即最多一个值),因此它与Mono<ServerResponse>
一起使用 - 该值将在内存中异步解析,并根据结果我们将返回不同的响应或手动处理业务异常。
在Flux
(即0..N值)的情况下,在任何给定时间都可能发生错误。
在这种情况下,您可以使用collectList
运算符将Flux<String>
转换为Mono<List<String>>
,并发出一个重要警告:所有元素都将缓冲在内存中。如果您的控制器/客户端依赖于流数据,那么数据流非常重要,这不是最佳选择。
我担心我没有更好的解决方案来解决这个问题,这就是原因:因为在Flux
期间任何时候都可能发生错误,所以无法保证我们可以更改HTTP状态和响应:事情可能已经被刷新了网络。当使用Spring MVC并返回InputStream
或Resource
时就已经是这种情况了。
Spring Boot错误处理功能尝试编写错误页面并更改HTTP状态(请参阅ErrorWebExceptionHandler
和实现类),但如果响应已提交,它将记录错误信息并让您知道HTTP状态可能是错误的。
我发现另一种方法来解决这个问题,在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错误代码。