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
相关推荐
憧憬成为java架构高手的小白2 分钟前
苍穹外卖--day09
java·spring boot·百度
狒狒热知识4 分钟前
2026年AI传播新闻软文营销发布当下178软文网领衔发展路径
大数据·人工智能
学代码的真由酱8 分钟前
Java多用户一对一网页聊天室-测试报告
java·开发语言·功能测试·测试
黑巧克力可减脂21 分钟前
以智录声,以技留韵:AI录音,解锁声音留存的古今新范式
人工智能
智慧景区与市集主理人29 分钟前
巨有科技景区智能导览告别传统讲解,打造沉浸式智慧游览体验
人工智能·科技·语音识别
Jasonakeke1 小时前
SpringBoot自动配置原理揭秘
java·spring boot·后端
keyanbanyungong1 小时前
告别杂乱病历!临床科研AI工具实测
人工智能·深度学习
出海小龙1 小时前
B2B 跟 B2C 的联盟营销有何根本区别?以及分别如何真正推动增长?
大数据·人工智能
xcLeigh1 小时前
聚合AI工具KULAAI:GPT、Claude、Gemini、DeepSeek热门模型一键使用
人工智能·gpt·claude·gemini·deepseek·聚合ai·kulaai
EnCi Zheng1 小时前
09aaac-RMSNorm是什么?
人工智能