处理Spring WebFlux中出现的错误

案例概述

在本教程中,我们将看一下处理Spring WebFlux项目中错误的各种策略,同时介绍一个实际案例。

我们还将指出在一个策略中使用另一个策略并在最后提供完整源代码的地址。

案例构建

对于我们的示例来说,我们将使用RESTful请求,该请求将用户名作为查询参数,并返回“Hello username”作为结果。

首先,让我们创建一个/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”字符串和用户名的方法:

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

只要使用用户名作为请求参数,例如,访问/hello?username=Tonni,则此请求将始终正常运行。

但是,如果我们在没有指定用户名的情况下调用相同的请求地址,例如/hello,它将抛出异常。

下面,我们将了解在何处以及如何重新组织我们的代码来处理WebFlux中的异常。

在功能级别上处理错误

MonoFlux APIs内置了两个关键操作符,用于处理功能级别上的错误。

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

使用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”结果。

使用onErrorResume处理错误

我们可以使用三种方法在onErrorResume上处理错误:

  • 计算动态fallback值
  • 使用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()抛出异常时,我们就会调用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的自定义异常。

在全局级别上处理错误

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

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

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

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

public class GlobalErrorAttributes extends DefaultErrorAttributes{@Overridepublic 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 extendsAbstractErrorWebExceptionHandler {// constructors@Overrideprotected 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对象将是我们在网络异常处理程序的构造函数传递一个的精确副本。理想情况下,这应该是我们自定义的Error Attributes类。

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

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

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

案例结论

在案例中,我们研究了处理Spring WebFlux项目中错误的各种策略,并指出了各种策略的优势。

处理Spring WebFlux中出现的错误相关推荐

  1. 在Spring WebFlux中创建多个RouterFunction

    在这篇文章中,我们将研究在Spring WebFlux中为不同的逻辑域定义多个路由器功能. 如果您正在创建"微服务",则可能不会出现问题,因为您很可能仅在每个服务的单个域中工作,但 ...

  2. 在Spring data中使用r2dbc

    文章目录 简介 依赖关系 数据库连接配置 数据库初始化 DAO操作 Service操作和Transaction controller 测试 简介 上篇文章我们讲到了怎么在Spring webFlux中 ...

  3. Spring Webflux – Kotlin DSL –实现的演练

    在先前的博客文章中,我描述了Spring Web Framework中的响应式编程支持Spring Webflux如何使用基于Kotlin的DSL使用户能够以非常直观的方式描述路由. 在这里,我想探索 ...

  4. 错误处理在Spring Integration中如何工作

    1.引言 这篇文章的目标是向您展示将消息传递系统与Spring Integration结合使用时如何处理错误. 您将看到同步和异步消息传递之间的错误处理有所不同. 和往常一样,我将跳过聊天并继续进行一 ...

  5. HOW-TO:带有Spring MVC的Tomcat中的自定义错误页面

    默认的Tomcat错误页面看起来很可怕. 此外,它们可能会公开有价值的信息,包括服务器版本和异常堆栈跟踪. Servlet规范提供了一种通过web.xml配置异常行为的方法. 可以配置对特定Java异 ...

  6. springboot异步注解_Spring Boot 2 :Spring Boot 中的响应式编程和 WebFlux 入门

    [小宅按]Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕. WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可 ...

  7. java中spring的web支持nio,Spring WebClient NIO功能和问题域,与Spring Webflux一起使用

    我正在使用最新版本的Spring - Spring 5 . 我正在开发http客户端的WebService"聚合器",有点像路由请求到外部WebServices,接收响应后接收响应 ...

  8. (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...

  9. Spring学习中使用javaConfig进行配置时出现 has not been refreshed yet错误

    Spring学习中使用javaConfig进行配置时出现 has not been refreshed yet错误 java.lang.IllegalStateException: org.sprin ...

最新文章

  1. MVC3教程之新手入门(转)
  2. 学习笔记Flink(八)—— 基于Flink 在线交易反欺诈检测
  3. [转载] 杜拉拉升职记——06 预算与排期
  4. vSphere 4系列之六:Standard vSwitch
  5. Spring boot的简单用法
  6. ubuntu下git更改默认编辑器
  7. javascript 通过地址获取经纬度 get lat long from address
  8. java elasticsearch_在Spring java框架中使用ElasticSearch的最佳方式
  9. 从汇编的眼光看C++(之delete内存泄露)
  10. Nopcommerce主要用到的技术及特点
  11. SQL Server 索引基础知识(10)----Join 时的三种算法简介
  12. [转载] python 使用pandas进行读写excel文件操作
  13. [Node.js]操作redis
  14. android 车载蓝牙音乐介绍
  15. pythoninstaller打包 其他电脑无法运行_Pyininstaller一个软件包故障坑,Pyinstaller,打包,失败,的...
  16. 【leetcode.179】最大数
  17. dlib人脸识别代码解读
  18. Spark 安装与配置 (Spark HA 集群部署)
  19. 系列报道 | 组织范式“青色组织”兴起:员工骨子里透出愉悦积极气质
  20. 将 Amazon EC2 到 Amazon S3 的数据传输推向100Gbps线速

热门文章

  1. c linux 获取cpuid_[C] 在GCC中获取CPUID信息(兼容VC)
  2. 解读功利主义——读《渴望崇高》有感2000字
  3. Linux内核移植流程 应该怎么开始着手
  4. Arduino的智能语音输入实现——Arduino与LU-ASR01的连接
  5. 软件测试工程师常见面试题
  6. 天才少年熊罗源(Alex Xiong),在美职场搅动风云
  7. 条码标签打印机可能遇到哪些问题
  8. 有赞、微盟“卷”向海外
  9. 梁昌勇 软件工程_梁昌勇简介_研究领域_学术成果_合肥工业大学管理学院教授-教师点评 - 人大经济论坛...
  10. uniapp获得经纬度和城市