在spring-webflux中处理错误的正确方法是什么?

我一直在使用spring-webflux做一些研究,我想知道什么应该是正确的方式来处理错误使用路由器功能。

我创建了一个小项目来测试几个场景,我喜欢得到关于它的反馈,看看其他人在做什么。

到目前为止,我所做的是。

给出以下路由功能:

@Component public class HelloRouter { @Bean RouterFunction<?> helloRouterFunction() { HelloHandler handler = new HelloHandler(); ErrorHandler error = new ErrorHandler(); return nest(path("/hello"), nest(accept(APPLICATION_JSON), route(GET("/"), handler::defaultHello) .andRoute(POST("/"), handler::postHello) .andRoute(GET("/{name}"), handler::getHello) )).andOther(route(RequestPredicates.all(), error::notFound)); } } 

我已经在我的处理程序上做了这个

 class HelloHandler { private ErrorHandler error; private static final String DEFAULT_VALUE = "world"; HelloHandler() { error = new ErrorHandler(); } private Mono<ServerResponse> getResponse(String value) { if (value.equals("")) { return Mono.error(new InvalidParametersException("bad parameters")); } return ServerResponse.ok().body(Mono.just(new HelloResponse(value)), HelloResponse.class); } Mono<ServerResponse> defaultHello(ServerRequest request) { return getResponse(DEFAULT_VALUE); } Mono<ServerResponse> getHello(ServerRequest request) { return getResponse(request.pathVariable("name")); } Mono<ServerResponse> postHello(ServerRequest request) { return request.bodyToMono(HelloRequest.class).flatMap(helloRequest -> getResponse(helloRequest.getName())) .onErrorResume(error::badRequest); } } 

他们是我的错误处理程序:

 class ErrorHandler { private static Logger logger = LoggerFactory.getLogger(ErrorHandler.class); private static BiFunction<HttpStatus,String,Mono<ServerResponse>> response = (status,value)-> ServerResponse.status(status).body(Mono.just(new ErrorResponse(value)), ErrorResponse.class); Mono<ServerResponse> notFound(ServerRequest request){ return response.apply(HttpStatus.NOT_FOUND, "not found"); } Mono<ServerResponse> badRequest(Throwable error){ logger.error("error raised", error); return response.apply(HttpStatus.BAD_REQUEST, error.getMessage()); } } 

以下是完整的示例回购:

https://github.com/LearningByExample/reactive-ms-example

Spring 5提供了一个WebHandler ,在JavaDoc中有这样一行:

使用HttpWebHandlerAdapter来使WebHandler适应HttpHandler。 WebHttpHandlerBuilder提供了一个方便的方法,同时还可以选择配置一个或多个过滤器和/或异常处理程序。

目前,官方文档建议我们应该在启动任何服务器之前将路由器功能封装到HttpHandler中:

 HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction); 

在WebHttpHandlerBuilder的帮助下,我们可以配置自定义异常处理程序:

 HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(toHttpHandler(routerFunction)) .prependExceptionHandler((serverWebExchange, exception) -> { /* custom handling goes here */ return null; }).build(); 

为什么不通过抛出处理函数的异常并实现自己的WebExceptionHandler来捕获它们:

 @Component class ExceptionHandler : WebExceptionHandler { override fun handle(exchange: ServerWebExchange?, ex: Throwable?): Mono<Void> { /* Handle different exceptions here */ when(ex!!) { is NoSuchElementException -> exchange!!.response.statusCode = HttpStatus.NOT_FOUND is Exception -> exchange!!.response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR } /* Do common thing like logging etc... */ return Mono.empty() } } 

上面的例子是在Kotlin中,因为我只是复制粘贴它从我目前正在处理的项目,因为原来的问题没有被标记为Java。

我目前正在做的只是提供一个bean我的WebExceptionHandler:

 @Bean @Order(0) public WebExceptionHandler responseStatusExceptionHandler() { return new MyWebExceptionHandler(); } 

比自己创建HttpHandler的好处是,如果我提供自己的ServerCodecConfigurer或者使用SpringSecurity ,我可以更好地与WebFluxConfigurer进行SpringSecurity