我正在尝试使用 WebFlux,但我看到了一个我不太明白的行为,我怀疑这是 WebFlux 或 Reactor 中的错误,但我需要确认。

我试图创建一个最小可重现的案例,它由一个 非常 简单的 HandlerFunction 组成,它尝试返回 200 响应,但在主体创建期间抛出异常,然后尝试使用 onErrorResume 来代替返回 404 响应。

处理程序看起来像这样:

public Mono<ServerResponse> reproduce(ServerRequest request){
        return ServerResponse.ok()
        .contentType(APPLICATION_JSON)
        .body(Mono.fromCallable(this::trigger),String.class)
        .onErrorResume(MinimalExampleException.class,e->ServerResponse.notFound().build());
}

我希望在调用关联的端点时会得到 404 响应。相反,我看到的是带有日志消息的 500 响应,表明 Spring 认为在请求处理期间存在未处理的异常。

当我在 onErrorResume 内设置断点时,我看到两个处理程序正在注册,一个是我在上面的方法中注册的,另一个是 Spring(在 RouterFunctions.toHttpHandler 内部)为 ResponseStatusException 的实例注册的。然后在处理请求的过程中,我只看到第二个处理程序(由 Spring 注册的处理程序)被调用,与抛出的异常不匹配,然后下降到根级处理程序。

据我所知,Spring 正在路由器级别覆盖 onErrorResume,以防止调用我在 Handler 中注册的那个。这是预期的行为吗?有没有更好的方法来完成我正在尝试的事情?

最佳答案

该框架确实有一个“包罗万象”的功能,可以在调用 .body(...) 之后的任何内容之前调用它。这是设计使然,我认为这很难避免。

我看到 3 个解决方案:

  • 围绕
  • 转动算子链

    像这样:
    return Mono.fromCallable(this::trigger)
               .flatMap(s -> ServerResponse.ok()
                            .contentType(MediaType.TEXT_PLAIN)
                            .syncBody(s))
               .onErrorResume(MinimalExampleException.class,
                            e -> ServerResponse.notFound().build());
    
  • 使用 ResponseStatusException

  • 您可以将 onErrorResumefromCallable() 放在同一级别(在 body 调用中),以通过错误单声道将特定错误转换为 ResponseStatusException:
    Mono.fromCallable(this::trigger)
        .onErrorResume(MinimalExampleException.class,
            e->Mono.error(new ResponseStatusException(404, "reason message", e)))
    
  • 使用异常处理程序

  • 您应该能够使用 @ExceptionHandler 注释方法来处理您的特定异常。

    关于java - onErrorResume 未按预期工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44273112/

    10-10 06:13