onErrorResume 没有按预期工作
onErrorResume not working as expected
我正在尝试使用 WebFlux,但我看到了一个我不太了解的行为,我怀疑这是 WebFlux 或可能是 Reactor 中的错误,但我需要确认。
我试图创建一个最小可重现的案例,它由一个 非常 简单的 HandlerFunction 组成,它尝试 return 一个 200 响应,但在主体期间抛出异常创建,然后尝试使用 onErrorResume 代替 return 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 中注册的那个。这是预期的行为吗?有没有更好的方法来完成我正在尝试的事情?
该框架确实有一个 "catch-all",它在调用 .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
您可以将 onErrorResume
放在与 fromCallable()
相同的级别(在主体调用内)以通过错误单声道将特定错误转换为 ResponseStatusException:
Mono.fromCallable(this::trigger)
.onErrorResume(MinimalExampleException.class,
e->Mono.error(new ResponseStatusException(404, "reason message", e)))
- 使用异常处理程序
您应该能够使用 @ExceptionHandler
注释方法来处理您的特定异常。
我正在尝试使用 WebFlux,但我看到了一个我不太了解的行为,我怀疑这是 WebFlux 或可能是 Reactor 中的错误,但我需要确认。
我试图创建一个最小可重现的案例,它由一个 非常 简单的 HandlerFunction 组成,它尝试 return 一个 200 响应,但在主体期间抛出异常创建,然后尝试使用 onErrorResume 代替 return 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 中注册的那个。这是预期的行为吗?有没有更好的方法来完成我正在尝试的事情?
该框架确实有一个 "catch-all",它在调用 .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
您可以将 onErrorResume
放在与 fromCallable()
相同的级别(在主体调用内)以通过错误单声道将特定错误转换为 ResponseStatusException:
Mono.fromCallable(this::trigger)
.onErrorResume(MinimalExampleException.class,
e->Mono.error(new ResponseStatusException(404, "reason message", e)))
- 使用异常处理程序
您应该能够使用 @ExceptionHandler
注释方法来处理您的特定异常。