
在 Reactor 中,需通过 Mono.error() 显式终止流并触发错误信号,而非在 doOnNext 中抛出异常;推荐使用 flatMap 封装校验逻辑,确保异常能正确传播并被重试机制捕获。
在 reactor 中,需通过 `mono.error()` 显式终止流并触发错误信号,而非在 `doonnext` 中抛出异常;推荐使用 `flatmap` 封装校验逻辑,确保异常能正确传播并被重试机制捕获。
在响应式编程中,Mono 是一个异步、非阻塞的单值发布者,其错误处理机制与传统同步代码有本质区别:不能依赖 throw 语句直接中断流,因为 doOnNext 等副作用操作(side-effect operators)仅用于“观察”数据,不参与数据转换或错误传播——在其中抛出异常会导致未定义行为(如丢失错误信号、绕过错误处理器),且无法被 @Retryable 或 retry() 等操作符识别。
正确的做法是:将业务校验逻辑嵌入到数据转换链中,用 flatMap 将原始 Mono
以下为推荐实现:
public Mono<response> handleResponse() {
return userService.getUser()
.flatMap(response -> {
try {
validate(response.getData()); // 若校验失败,抛出 RuntimeException
return Mono.just(response); // 校验通过,继续下游
} catch (Throwable t) {
return Mono.error(t); // 显式转为错误信号
}
})
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)) // 可选:内置重试
.filter(throwable -> throwable instanceof RuntimeException));
}</response>
⚠️ 注意事项:
- ❌ 避免在 doOnNext、doOnError、doFinally 等 doOn* 系列操作符中抛出异常——它们不改变数据流,仅执行副作用;
- ✅ flatMap 是核心:它允许你基于上游值动态返回一个新的 Mono,从而精确控制成功/失败路径;
- ✅ 若使用 Spring Retry(如 @Retryable),需确保异常真实触发 onError 事件,否则注解无效(因 AOP 代理仅拦截方法级异常,而响应式流的错误发生在订阅时);
- ✅ 推荐对 validate() 方法做防御性封装,捕获所有 Throwable(包括 Error),再根据策略决定是否包装为 Mono.error()(通常建议仅传播 RuntimeException 及其子类,避免误捕 OutOfMemoryError 等严重错误)。
总结:响应式流中的“显式抛异常”,本质是用 Mono.error() 主动发出错误信号,而非语法层面的 throw。这既是 Reactor 的设计契约,也是保障重试、熔断、日志等响应式运维能力的前提。











