在 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

原文由 Juan Medina 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 568
2 个回答

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();

原文由 aietcn 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您认为路由器函数不是处理异常的正确位置,您可以抛出 HTTP 异常,这将导致正确的 HTTP 错误代码。对于 Spring-Boot(也是 webflux),这是:

   import org.springframework.http.HttpStatus;
  import org.springframework.web.server.ResponseStatusException;
  .
  .
  .

  new ResponseStatusException(HttpStatus.NOT_FOUND,  "Collection not found");})

spring securities AccessDeniedException 也将得到正确处理(403/401 响应代码)。

如果你有一个微服务,并且想为它使用 REST,这可能是一个不错的选择,因为那些 http 异常非常接近业务逻辑,在这种情况下应该放在业务逻辑附近。而且由于在微服务中你不应该有太多的业务逻辑和异常,它也不应该使你的代码混乱……(当然,这一切都取决于)。

原文由 Frischling 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题