Spring webflux 中的异常处理

Exception Handling in Spring webflux

我正在使用反应流开发一个 Spring webflux 项目。我有一个如下的用例,想知道如何以反应方式完成它。

  @RestController
  public class Example {

    @GetMapping("/greet")
    public Mono<String> Test() {
       return Mono.just("Tim")
               .map(s -> s.toUpperCase())
               .map(s -> s.toLowerCase())
               .doOnSuccess(s -> validate(s)) // usecase is to validate here in middle of the pipeline
               .onErrorResume(ex -> Mono.just("Guest"))
               .map(s -> "Hi, "+s);
    }
   
  public void validate(String s) {
    if(s.length() < 5) {throw new RuntimeException("Name is short");}
  }
 
}

我知道这是一个人为的例子,但我有类似的东西。我认为在命中端点时抛出错误会导致浏览器屏幕出现异常。但令我惊讶的是它转到 onErrorResume() 并且我得到了 Hi, Guest 作为响应。我想当throw用于在反应管道组装之前抛出异常时,它不会使用onErrorResume()。我在这里错过了什么?

还有问题 #2,如果我使用 Mono.error(new RuntimeException("Name is short")) 而不是 throw new RuntimeException("Name is short"),我该如何实现?有人可以回答我的两个问题吗?欢迎提出改进代码的建议。

对于第 1 个问题,您可以在 onErrorResume

中添加谓词
.onErrorResume(e -> !(e instanceof RuntimeException), ex -> Mono.just("Guest"))

这样您就可以过滤出您可以 return 预定义结果的错误。

对于问题 #2,您可以将消费者 doOnSuccess 替换为 flatMap 和 return Mono for validate 方法:

    public Mono<String> Test() {
        return Mono.just("Tim")
                .map(s -> s.toUpperCase())
                .map(s -> s.toLowerCase())
                .flatMap(s -> validate(s))
                .onErrorResume(e -> !(e instanceof RuntimeException), ex -> Mono.just("Guest"))
                .map(s -> "Hi, " + s);
    }

    public Mono<String> validate(String s) {
        return (s.length() < 5) ?
                Mono.error(() -> new RuntimeException("Name is short")) :
                Mono.just(s);
    }

I thought when throw is used to throw an exception before the reactive pipeline is assembled, it will not use onErrorResume()

Mono::doOnSuccess 执行时间 Mono 成功完成(管道已经组装)时触发。

请注意,在 doOnNextmap 等中间运算符中,您可以自由抛出异常,因为 Reactor 可以将它们转换为正确的错误信号,因为此时 Mono 已经在进步。

how can I achieve this if I'm using Mono.error(new RuntimeException("Name is short")) instead of throw new RuntimeException("Name is short")?

您可以将 doOnSuccessmap 替换为 handle 运算符:

 return Mono.just("Tim")
            .handle((name, sink) -> {
                if(name.length() < 5){
                    sink.error(new RuntimeException("Name is short"));
                } else {
                    sink.next(name.toLowerCase());
                }
            })