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
相关推荐
电商API&Tina2 小时前
电商数据采集API接口||合规优先、稳定高效、数据精准
java·javascript·数据库·python·json
AI专业测评2 小时前
文本降熵与反检测:2026年6款AI写网文大模型与消除AIGC痕迹专业工具实测(附官网)
人工智能·aigc
七夜zippoe2 小时前
OpenClaw 接入 Discord:从零开始
大数据·人工智能·microsoft·discord·openclaw
知识领航员2 小时前
咖啡店BGM:如何用AI生成“循环一天也不腻”的氛围音乐?
人工智能
北京软秦科技有限公司2 小时前
AI报告审核守护公共卫生安全:IACheck助力公共纺织品卫生检测报告合规与健康保障
大数据·人工智能·安全
TMT星球2 小时前
金山办公2025年财报:营收净利双增,WPS 365业务同比增长64.93%
人工智能·wps
PythonFun2 小时前
WPS AI助力字母序号高效填充:四种快捷方法
人工智能·wps
Techblog of HaoWANG2 小时前
目标检测与跟踪(12)-- Jetson Xavier NX / Orin NX ROS及视觉检测环境配置、移植、部署指南
人工智能·目标检测·计算机视觉·机器人·视觉检测·控制
杀生丸学AI2 小时前
【世界模型】video2world:从不一致视角重建世界
人工智能·三维重建·扩散模型·具身智能·视频生成·世界模型·空间智能