使用 webflux 处理异常并返回正确的 HTTP 代码
Posted
技术标签:
【中文标题】使用 webflux 处理异常并返回正确的 HTTP 代码【英文标题】:Handling exceptions and returning proper HTTP code with webflux 【发布时间】:2018-07-20 13:55:55 【问题描述】:我正在使用 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());
我实际上对这种行为感到惊讶,这是一个错误吗?
【问题讨论】:
【参考方案1】:我找到了解决此问题的另一种方法,在 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 错误代码。
【讨论】:
【参考方案2】:您的第一个示例使用Mono
(即最多一个值),因此它与Mono<ServerResponse>
配合得很好-该值将在内存中异步解析,并且根据结果我们将返回不同的响应或处理业务手动异常。
如果是 Flux
(即 0..N 个值),则可能在任何给定时间发生错误。
在这种情况下,您可以使用collectList
运算符将您的Flux<String>
转换为Mono<List<String>>
,并带有一个很大的警告:所有元素都将缓冲在内存中。如果数据流很重要,或者您的控制器/客户端是否依赖流数据,这不是这里的最佳选择。
恐怕我没有更好的解决方案来解决这个问题,原因如下:由于Flux
期间随时可能发生错误,因此无法保证我们可以更改 HTTP 状态和响应:事情可能已经在网络上刷了。在使用 Spring MVC 并返回 InputStream
或 Resource
时,情况已经如此。
Spring Boot 错误处理功能尝试编写错误页面并更改 HTTP 状态(请参阅ErrorWebExceptionHandler
和实现类),但如果响应已经提交,它将记录错误信息并让您知道 HTTP状态可能是错误的。
【讨论】:
谢谢,很好的解释!很难完全摆脱旧的同步思维 :) 为了解决我的问题,我用其他方法更改了我的服务 API,以便在调用异步调用之前执行这些检查。 我在this post添加了一些例子以上是关于使用 webflux 处理异常并返回正确的 HTTP 代码的主要内容,如果未能解决你的问题,请参考以下文章
为啥要在 Webflux 应用程序中构建自己的错误/异常处理?
在身份验证 Spring Security + WebFlux 期间抛出和处理自定义异常
WebFlux 功能:如何检测空 Flux 并返回 404?