WebFlux onErrorContinue 和 onErrorResume使用详解

独立使用

在 Project Reactor 中,onErrorResume 和 onErrorContinue 都是处理流中异常的常用方法,但它们在流的生命周期控制 和应用场景上有本质区别:

  1. onErrorResume (降级/备选方案)

当流中发生错误时,onErrorResume 会捕获异常并切换 到一个新的 Publisher(备选流),原有的流会在此处终止。

  • 行为 :类似于 Java 中的 try-catch 块中 catch 后的 return fallbackValue。

  • 流的状态:上游流发生错误后不再发送后续元素,转而由你提供的备选流发送数据并正常结束。

  • 示例代码 :

    复制代码
    Flux.just(1, 2, 0, 4)
        .map(i -> 10 / i) // 当 i 为 0 时触发异常
        .onErrorResume(e -> Flux.just(-1, -2)) // 发生错误后,原有流结束,开始发送 -1, -2
        .subscribe(System.out::println); 
    // 输出:10, 5, -1, -2
  1. onErrorContinue (跳过/继续执行)

onErrorContinue 允许你在发生错误时丢弃 导致错误的元素,并继续处理流中的后续元素。

  • 行为 :类似于在 for 循环中使用 try-catch 并执行 continue。

  • 流的状态 :流不会终止。它会针对当前错误元素执行回调逻辑(如打日志),然后请求上游发送下一个元素。

  • 示例代码 :

    复制代码
    Flux.just(1, 2, 0, 4)
        .map(i -> 10 / i)
        .onErrorContinue((e, val) -> System.err.println("Error on " + val)) // 仅跳过错误元素
        .subscribe(System.out::println);
    // 输出:10, 5, (打印错误日志), 2.5

核心对比总结

特性 onErrorResume onErrorContinue
主要目的 错误恢复/降级(Fallback) 容错处理/跳过(Skip)
流的命运 终止原有的流,切换到新流 维持原有的流,处理后续元素
适用场景 数据库查询失败返回缓存数据 批量处理中某一条记录损坏,不影响其他记录
层级影响 仅影响当前位置之后的链式调用 具有"上溯"特性,会影响上游的操作算子

⚠️ 使用建议

  1. 谨慎使用 onErrorContinue:它会改变上游算子的默认行为(让本该终止的流强行继续),有时会导致难以排查的副作用或资源泄漏。

  2. 局部处理优先 :如果你只想在 flatMap 内部某次调用出错时不影响整个流,建议在 flatMap 内部使用 onErrorResume 返回 Mono.empty(),这比全局使用 onErrorContinue 更安全、更符合响应式语义。

    nurkiewicz.com +1

onErrorResume() 然后 onErrorContinue()

复制代码
public static void main(String... args) {
    Flux.range(1,5)
            .doOnNext(i -> System.out.println("input=" + i))
            .map(i -> i == 2 ? i / 0 : i)
            .map(i -> i * 2)
            .onErrorResume(err -> {
                log.info("onErrorResume");
                return Flux.empty();
            })
            .onErrorContinue((err, i) -> {log.info("onErrorContinue={}", i);})
            .reduce((i,j) -> i+j)
            .doOnNext(i -> System.out.println("sum=" + i))
            .block();
}

输出如下:

复制代码
input=1
input=2
17:47:05.789 [main] INFO com.example.demo.config.TestRunner - onErrorContinue=2
input=3
input=4
input=5
sum=26

这样的结果,你想到了吗?onErrorContinue() 会在 onErrorResume() 得到错误之前处理这个错误。当两个错误处理函数在同一个函数中的时候很明显,但是当你的函数中只有 onErrorResume(),而一些调用者实际上有 onErrorContinue() 时,你的 onErrorResume() 没有被调用的原因可能就不那么明显了。

使用 onErrorResume() 模拟 onErrorContinue()

有些博客建议我们完全不用 onErrorContinue(),且在所有场景中仅用 onErrorResume()。但是上述示例已经展示了它们会产生不同的结果。那我们怎么实现呢?

复制代码
public static void main(String... args) {
    Flux.range(1,5)
            .doOnNext(i -> System.out.println("input=" + i))
            .flatMap(i -> Mono.just(i)
                    .map(j -> j == 2 ? j / 0 : j)
                    .map(j -> j * 2)
                    .onErrorResume(err -> {
                        System.out.println("onErrorResume");
                        return Mono.empty();
                    })
            )
            .reduce((i,j) -> i+j)
            .doOnNext(i -> System.out.println("sum=" + i))
            .block();
}

因此,本质上是将可能在 flatMap 或 concatMap 中抛出错误的操作包装起来,并在其上使用 onErrorResume()。这样,它会产生相同的结果:

复制代码
input=1
input=2
onErrorResume
input=3
input=4
input=5
sum=26

使用 onErrorResume() 和下游的 onErrorContinue() 模拟 onErrorContinue()

有时候,onErrorContinue() 放在调用程序中,您无法控制它。但你仍然需要 onErrorResume()。你该怎么办?

复制代码
public static void main(String... args) {
    Flux.range(1,5)
            .doOnNext(i -> System.out.println("input=" + i))
            .flatMap(i -> Mono.just(i)
                    .map(j -> j == 2 ? j / 0 : j)
                    .map(j -> j * 2)
                    .onErrorResume(err -> {
                        System.out.println("onErrorResume");
                        return Mono.empty();
                    })
                    .onErrorStop()
            )
            .onErrorContinue((err, i) -> {log.info("onErrorContinue={}", i);})
            .reduce((i,j) -> i+j)
            .doOnNext(i -> System.out.println("sum=" + i))
            .block();
}

秘诀是在 onErrorResume() 代码块的末尾添加 onErrorStop() ------这会阻塞 onErrorContinue(),这样它就不会在 onErrorResume() 之前占用错误。尝试删除 onErrorStop(),你会看到 onErrorContinue() 在 onErrorResume 之前弹出。

输出为:

复制代码
input=1
input=2
onErrorResume
input=3
input=4
input=5
sum=26
相关推荐
system_error_x12 分钟前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
驭渊的小故事42 分钟前
Spring AI Alibaba 实战:从maven依赖治理到声明式工具调用
java·人工智能·spring
北京中科新远科技1 小时前
高速光链路健康检查实战:DOM、FEC、误码与压力回归
人工智能·数据挖掘·回归
火山引擎和TA的超级拍档们1 小时前
超级拍档・光影新生|火山引擎 AIGC 主题峰会回顾
人工智能
冬奇Lab1 小时前
一天一个开源项目(第245篇):Raven —— ‘Harness 的 Harness‘,把 Claude Code、Codex 等智能体编排起来并让它递归自我改进
人工智能·开源·资讯
工业视觉老A1 小时前
攻克牙膏朝向人工分拣痛点,AI 视觉检测保障包装工序稳定
人工智能·计算机视觉·视觉检测
smartpi_ai1 小时前
离线语音芯片怎么选:SU、CI、JX、JL 系列语音模块选型指南
人工智能·ci/cd·语音识别
Elastic 中国社区官方博客1 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1881 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
火山引擎开发者社区2 小时前
DeepSeek-V4.1-Flash 新版本登陆火山方舟,效果无损“经济版”八折上线
人工智能