【WebFlux】第四篇 —— 响应式异常处理与测试

发布时间:2026/7/20 19:51:00
【WebFlux】第四篇 —— 响应式异常处理与测试 告别 try-catch响应式异常处理机制在传统的同步编程中我们习惯用 try-catch 来捕获异常。但在响应式编程中由于代码是声明式的、异步执行的当异常在 map 或 flatMap 内部抛出时它不会中断当前线程而是作为一个“错误信号onError”沿着数据流向下游传播。如果这个信号没有被处理最终会导致整个订阅被终止。Reactor 提供了一套强大的操作符来优雅地处理这些错误onErrorReturn优雅降级当发生异常时直接返回一个默认的兜底值保证流不会中断。Flux.just(1,2,0,4).map(i-10/i)// 遇到 0 时会抛出 ArithmeticException.onErrorReturn(-1)// 捕获异常返回默认值 -1.subscribe(System.out::println);// 输出: 10, 5, -1onErrorResume切换备用流当发生异常时根据异常类型切换到另一个备用的 Publisher数据流。这在处理外部服务调用失败时非常有用。fetchFromPrimaryService().onErrorResume(TimeoutException.class,e-fetchFromBackupService())// 主服务超时自动切换备用服务.subscribe(System.out::println);onErrorMap异常转换将底层的异常如数据库报错转换为业务层更容易理解的自定义异常。userRepository.findById(id).onErrorMap(DataAccessException.class,e-newBusinessException(用户数据获取失败)).subscribe();全局异常拦截ControllerAdvice 的响应式改造除了流级别的处理Spring WebFlux 依然支持我们熟悉的 ControllerAdvice 进行全局异常拦截。需要注意的是在 WebFlux 中处理方法的返回值应该是响应式的 Mono。ControllerAdvicepublicclassGlobalExceptionHandler{ExceptionHandler(BusinessException.class)publicMonoResponseEntityErrorResponsehandleBusinessException(BusinessExceptionex){ErrorResponseerrornewErrorResponse(HttpStatus.BAD_REQUEST.value(),ex.getMessage());returnMono.just(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error));}}响应式自动化测试利器WebTestClient在 Spring WebFlux 中传统的 MockMvc 无法处理异步流因此官方提供了 WebTestClient。它基于 WebClient 构建专门用于对 WebFlux 端点进行非阻塞的断言测试。实战示例使用 WebFluxTest 进行控制器测试WebFluxTest(UserController.class)// 仅加载 WebFlux 相关的上下文启动极快classUserControllerTest{AutowiredprivateWebTestClientwebTestClient;MockBeanprivateUserServiceuserService;// 模拟 Service 层依赖TestvoidshouldReturnUserWhenExists(){// 1. 定义 Mock 行为Mockito.when(userService.findById(1)).thenReturn(Mono.just(newUser(1,Alice)));// 2. 发起请求并断言webTestClient.get().uri(/api/users/1).exchange()// 执行请求.expectStatus().isOk()// 断言 HTTP 状态码为 200.expectBody()// 断言响应体内容.jsonPath($.name).isEqualTo(Alice);}}响应式流的单元测试StepVerifier如果要测试 Service 层返回的 Flux 或 MonoWebTestClient 就不适用了。此时我们需要引入 reactor-test 依赖并使用 StepVerifier。它是验证异步序列的绝对利器。实战示例验证 Flux 流的行为TestvoidtestUserStream(){FluxStringuserStreamuserService.getActiveUsers();StepVerifier.create(userStream).expectNext(Alice)// 期望第一个元素是 Alice.expectNextMatches(name-name.startsWith(B))// 期望第二个元素以 B 开头.expectNextCount(3)// 期望接下来还有 3 个元素.expectComplete()// 期望流正常结束.verify(Duration.ofSeconds(5));// 设置超时时间防止流卡死}本篇小结响应式编程中的异常处理分为“流级别的操作符降级”和“全局级别的统一拦截”。而在测试方面WebTestClient 和 StepVerifier 是验证响应式逻辑正确性的左膀右臂。下一步预告至此我们已经掌握了 Reactor 的核心语法。下一篇笔记我们将正式回到 Spring WebFlux 框架对比“基于注解的 Controller”与“函数式端点Router Functions”两种编程模型并学习如何使用 WebClient 发起非阻塞的外部 HTTP 调用。准备好进入真正的 Web 开发了吗