zoukankan      html  css  js  c++  java
  • 【】在Spring WebFlux中处理错误

    原文链接:http://www.baeldung.com/spring-webflux-errors

    1. 概览

    在本教程中,我们通过一个实际的例子来看一下可用于处理Spring WebFlux项目中的错误的各种策略

    我们还将指出在哪种情况下使用一种策略会比另外一种好,在本文最后将提供所有源码的下载地址。

    2. 配置实例

    上一篇文章 previous article 中已经提到了maven的配置, 并对 Spring Webflux做了简单的介绍。

    在这个例子中,我们为一个 RESTful 端点加上一个名为 username 的查询参数,并以“Hello username”作为结果返回。

    First, let’s create a router function that routes the /hello request to a method named handleRequest in the passed-in handler:

    首先,让我们创建一个路由器函数,将/hello请求路由名为handleRequest的方法中:

    @Bean
    public RouterFunction<ServerResponse> routeRequest(Handler handler) {
        return RouterFunctions.route(RequestPredicates.GET("/hello")
          .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), 
            handler::handleRequest);
        }

    接下来,我们将定义handleRequest()方法,该方法调用sayHello()方法并在ServerResponse主体中包含/返回其结果的方法:

    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return
          //...
            sayHello(request)
          //...
    }

    最后,sayHello()是一个简单的实用工具方法,它将“Hello”和 username 连接起来返回。

    private Mono<String> sayHello(ServerRequest request) {
        //...
        return Mono.just("Hello, " + request.queryParam("name").get());
        //...
    }

    只要用 username 作为我们请求的一部分存在,例如使用“/hello?username=Tonni”访问,我们的端点就可以正确运行。

    然而,如果我们调用"/hello"的时候没有使用 username 这个参数,它会抛出一个异常。

    下面,我们将看看我们在何处如何重新组织我们的代码才能在WebFlux中处理此异常。

    3. 在函数级别处理错误

    Mono和Flux API内置了两个关键操作符,用于处理功能级别的错误。

    让我们简要地探讨它们及其用法。

    3.1. 使用 onErrorReturn

    当出现错误时,我们可以使用 onErrorReturn()来返回一个静态的默认值。

    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return sayHello(request)
          .onErrorReturn("Hello Stranger")
          .flatMap(s -> ServerResponse.ok()
          .contentType(MediaType.TEXT_PLAIN)
          .syncBody(s));
    }

    sayHello()抛出异常时,函数就会默认返回"Hello Stranger"。

    3.2. 使用onErrorResume

    使用onErrorResume处理错误有三种方式:

    • 计算动态返回值
    • 使用fallback方法 跳转到备份路径
    • 捕获,包装和重新抛出错误,例如 作为自定义业务异常

    让我们看看怎么杨计算一个值:

    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return sayHello(request)
          .flatMap(s -> ServerResponse.ok()
          .contentType(MediaType.TEXT_PLAIN)
              .syncBody(s))
            .onErrorResume(e -> Mono.just("Error " + e.getMessage())
              .flatMap(s -> ServerResponse.ok()
                .contentType(MediaType.TEXT_PLAIN)
                .syncBody(s)));
    }

    在这里,每当sayHello()抛出异常时,我们将返回一个字符串,该字符串由附加到字符串“Error”的动态获取的错误消息组成。

    接下来,当错误发生时我们调用 fallback 方法:

    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return sayHello(request)
          .flatMap(s -> ServerResponse.ok()
          .contentType(MediaType.TEXT_PLAIN)
          .syncBody(s))
          .onErrorResume(e -> sayHelloFallback()
          .flatMap(s ->; ServerResponse.ok()
          .contentType(MediaType.TEXT_PLAIN)
          .syncBody(s)));
    }

    在这里,只要sayHello()抛出异常,我们就会调用替代方法sayHelloFallback()。

    使用onErrorResume()的最后一个选项是捕获,包装和重新抛出错误,例如 作为NameRequiredException

    public Mono<ServerResponse> handleRequest(ServerRequest request) {
        return ServerResponse.ok()
          .body(sayHello(request)
          .onErrorResume(e -> Mono.error(new NameRequiredException(
            HttpStatus.BAD_REQUEST, 
            "username is required", e))), String.class);
    }

    在这里,只要sayHello()抛出异常,我们就会抛出一个自定义异常,并带有消息:"username is required"。

    4. 全局级别的错误处理

    到目前为止,我们提供的所有示例都在函数级别上处理了错误处理。

    但是,我们可以选择在全局范围内处理我们的WebFlux错误。 要做到这一点,我们只需要采取两个步骤:

    • 自定义全局错误响应属性
    • 实现全局错误处理程序

    我们的处理程序抛出的异常将被自动转换为HTTP状态和JSON错误正文。 要自定义这些,我们可以简单地扩展DefaultErrorAttributes类并覆盖其getErrorAttributes()方法:

    public class GlobalErrorAttributes extends DefaultErrorAttributes{
         
        @Override
        public Map<String, Object> getErrorAttributes(ServerRequest request, 
          boolean includeStackTrace) {
            Map<String, Object> map = super.getErrorAttributes(
              request, includeStackTrace);
            map.put("status", HttpStatus.BAD_REQUEST);
            map.put("message", "username is required");
            return map;
        }
     
    }

    在这里,我们希望状态:BAD_REQUEST和消息:"username is required"在发生异常时作为错误属性的一部分返回。

    接下来,让我们实现全局错误处理程序。 为此,Spring提供了一个方便的AbstractErrorWebExceptionHandler类,供我们在处理全局错误时进行扩展和实现:

    @Component
    @Order(-2)
    public class GlobalErrorWebExceptionHandler extends
        AbstractErrorWebExceptionHandler {
     
        // constructors
     
        @Override
        protected RouterFunction<ServerResponse> getRoutingFunction(
          ErrorAttributes errorAttributes) {
     
            return RouterFunctions.route(
              RequestPredicates.all(), this::renderErrorResponse);
        }
     
        private Mono<ServerResponse> renderErrorResponse(
           ServerRequest request) {
     
           Map<String, Object> errorPropertiesMap = getErrorAttributes(request, false);
     
           return ServerResponse.status(HttpStatus.BAD_REQUEST)
             .contentType(MediaType.APPLICATION_JSON_UTF8)
             .body(BodyInserters.fromObject(errorPropertiesMap));
        }
    }

    在这个例子中,我们将全局错误处理程序的顺序设置为-2。 这是为了给它一个比在@Order(-1)注册的DefaultErrorWebExceptionHandler更高的优先级。

    errorAttributes对象将是我们在Web异常处理程序的构造函数中传递的副本的精确副本。 理想情况下,这应该是我们自定义的Error Attributes类。

    然后,我们清楚地说明我们想要将所有错误处理请求路由到renderErrorResponse()方法。

    最后,我们获取错误属性并将它们插入服务器响应主体中。

    然后,它会生成一个JSON响应,其中包含错误,HTTP状态和计算机客户端的异常消息的详细信息。 对于浏览器客户端,它有一个“whitelabel”错误处理程序,它以HTML格式呈现相同的数据。 当然,这可以是定制的。

    5. 结尾

    在本文中,我们研究了可用于处理Spring WebFlux项目中的错误的各种策略,并指出了使用一种策略而不是另一种策略的优势。

    正如所承诺的那样,本文附带的完整源代码可以在 GitHub获得。

  • 相关阅读:
    Filter&Listener
    jsp&mvc开发模式&jstl标签&三层架构
    Tomcat&Servlet
    xml
    SpringMVC
    io流-缓冲流
    io流-文件流节点流
    Io流
    JAVA中反射机制
    IDEA 将web项目部署到tomcat中运行
  • 原文地址:https://www.cnblogs.com/hanbin/p/14224684.html
Copyright © 2011-2022 走看看