WebFlux onErrorContinue 和 onErrorResume使用详解

独立使用

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

  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
相关推荐
庞轩px几秒前
第三篇:泛型深度解析——类型擦除与通配符的奥秘
java·编译·泛型·类型擦除
波动几何2 分钟前
CAD制图编辑器cad-editor
人工智能
耿雨飞6 小时前
第三章:LangChain Classic vs. 新版 LangChain —— 架构演进与迁移指南
人工智能·架构·langchain
BizViewStudio6 小时前
甄选 2026:AI 重构新媒体代运营行业的三大核心变革与落地路径
大数据·人工智能·新媒体运营·媒体
俊哥V6 小时前
AI一周事件 · 2026年4月8日至4月14日
人工智能·ai
GitCode官方7 小时前
G-Star Gathering Day 杭州站回顾
人工智能·开源·atomgit
宇擎智脑科技7 小时前
开源 AI Agent 架构设计对比:Python 单体 vs TypeScript 插件化
人工智能·openclaw·hermes agent
HoneyMoose7 小时前
Jenkins Cloudflare 部署提示错误
java·servlet·jenkins
阿丰资源7 小时前
基于SpringBoot的物流信息管理系统设计与实现(附资料)
java·spring boot·后端
Predestination王瀞潞8 小时前
Java EE3-我独自整合(第四章:Spring bean标签的常见配置)
java·spring·java-ee