我们如何将 @ExceptionHandler 与 spring 网络流量一起使用?
How could we use @ExceptionHandler with spring web flux?
在 spring web 中,我们可以使用注释 @ExceptionHandler 来处理控制器的服务器和客户端错误。
我尝试将此注释与 web-flux 控制器一起使用,它仍然对我有用,但经过一些调查后我发现 here
The situation with Spring Web Reactive is more complicated. Because
the reactive streams are evaluted by a different thread than the one
that executes the controllers method, the exceptions won’t be
propagated to the controller thread automatically. This means that the
@ExceptionHandler method will work only for exceptions that are thrown
in the thread that handles the request directly. Exceptions thrown in
the stream will have to be propagated back to the thread if we want to
use the @ExceptionHandler feature. This seems like a bit of a let down
but at the time of writing this Spring 5 is still not released so
error handling might still get better.
所以我的问题是如何将异常传播回线程。是否有关于使用 @ExceptionHandler 和 Spring web flux 的好例子或文章?
更新:
从spring.io看来是支持的,但还是缺乏大体的了解
谢谢,
您可以使用 @ExceptionHandler
带注释的方法来处理在执行 WebFlux 处理程序时发生的错误(例如,您的控制器方法)。使用 MVC 你确实也可以处理在映射阶段发生的错误,但 WebFlux 不是这样。
回到你的异常传播问题,你分享的文章不准确。
在响应式应用程序中,请求处理确实可以随时从一个线程跳到另一个线程,因此您不能再依赖“每个请求一个线程”模型(想想:ThreadLocal
)。
您真的不必考虑异常传播或线程的管理方式。例如,以下样本应该是等效的:
@GetMapping("/test")
public Mono<User> showUser() {
throw new IllegalStateException("error message!");
}
@GetMapping("/test")
public Mono<User> showUser() {
return Mono.error(new IllegalStateException("error message!"));
}
Reactor 将按照 Reactive Streams 合同中的预期将这些异常作为错误信号发送(有关更多信息,请参阅 the "error handling" documentation section)。
不是原始问题的确切答案,但将异常映射到 http 响应状态的快速方法是抛出 org.springframework.web.server.ResponseStatusException
/ 或创建自己的子类...
对 http 响应状态的完全控制 + spring 将添加一个响应主体,并可选择添加 reason
。
{
"timestamp": 1529138182607,
"path": "/api/notes/f7b.491bc-5c86-4fe6-9ad7-111",
"status": 400,
"error": "Bad Request",
"message": "For input string: \"f7b.491bc\""
}
现在可以在 Spring WebFlux 中使用 @ExceptionHandler
以及 @RestControllerAdvice
甚至 @ControllerAdvice
。
示例:
添加webflux依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
创建您的 class ExceptionHandler
@RestControllerAdvice
public class ExceptionHandlers {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandlers.class);
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String serverExceptionHandler(Exception ex) {
LOGGER.error(ex.getMessage(), ex);
return ex.getMessage();
}
}
创建控制器
@GetMapping(value = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Mono<String> exceptionReturn() {
return Mono.error(new RuntimeException("test error"));
}
此处提取的示例:
https://ddcode.net/2019/06/21/spring-5-webflux-exception-handling/
以下全局错误处理程序对我有用:
import org.springframework.web.server.ResponseStatusException;
@Slf4j
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MyCustomReactiveErrorHandling {
@ExceptionHandler(MyCustomNotFoundException.class)
public void handleMyCustomException(MyCustomNotFoundException ex) {
throw new ResponseStatusException(404, "Data not found!", ex);
}
}
抛出我的异常 returns 其余服务的正确 http 状态代码。
在 spring web 中,我们可以使用注释 @ExceptionHandler 来处理控制器的服务器和客户端错误。
我尝试将此注释与 web-flux 控制器一起使用,它仍然对我有用,但经过一些调查后我发现 here
The situation with Spring Web Reactive is more complicated. Because the reactive streams are evaluted by a different thread than the one that executes the controllers method, the exceptions won’t be propagated to the controller thread automatically. This means that the @ExceptionHandler method will work only for exceptions that are thrown in the thread that handles the request directly. Exceptions thrown in the stream will have to be propagated back to the thread if we want to use the @ExceptionHandler feature. This seems like a bit of a let down but at the time of writing this Spring 5 is still not released so error handling might still get better.
所以我的问题是如何将异常传播回线程。是否有关于使用 @ExceptionHandler 和 Spring web flux 的好例子或文章?
更新: 从spring.io看来是支持的,但还是缺乏大体的了解
谢谢,
您可以使用 @ExceptionHandler
带注释的方法来处理在执行 WebFlux 处理程序时发生的错误(例如,您的控制器方法)。使用 MVC 你确实也可以处理在映射阶段发生的错误,但 WebFlux 不是这样。
回到你的异常传播问题,你分享的文章不准确。
在响应式应用程序中,请求处理确实可以随时从一个线程跳到另一个线程,因此您不能再依赖“每个请求一个线程”模型(想想:ThreadLocal
)。
您真的不必考虑异常传播或线程的管理方式。例如,以下样本应该是等效的:
@GetMapping("/test")
public Mono<User> showUser() {
throw new IllegalStateException("error message!");
}
@GetMapping("/test")
public Mono<User> showUser() {
return Mono.error(new IllegalStateException("error message!"));
}
Reactor 将按照 Reactive Streams 合同中的预期将这些异常作为错误信号发送(有关更多信息,请参阅 the "error handling" documentation section)。
不是原始问题的确切答案,但将异常映射到 http 响应状态的快速方法是抛出 org.springframework.web.server.ResponseStatusException
/ 或创建自己的子类...
对 http 响应状态的完全控制 + spring 将添加一个响应主体,并可选择添加 reason
。
{
"timestamp": 1529138182607,
"path": "/api/notes/f7b.491bc-5c86-4fe6-9ad7-111",
"status": 400,
"error": "Bad Request",
"message": "For input string: \"f7b.491bc\""
}
现在可以在 Spring WebFlux 中使用 @ExceptionHandler
以及 @RestControllerAdvice
甚至 @ControllerAdvice
。
示例:
添加webflux依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
创建您的 class ExceptionHandler
@RestControllerAdvice public class ExceptionHandlers { private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandlers.class); @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public String serverExceptionHandler(Exception ex) { LOGGER.error(ex.getMessage(), ex); return ex.getMessage(); } }
创建控制器
@GetMapping(value = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Mono<String> exceptionReturn() { return Mono.error(new RuntimeException("test error")); }
此处提取的示例:
https://ddcode.net/2019/06/21/spring-5-webflux-exception-handling/
以下全局错误处理程序对我有用:
import org.springframework.web.server.ResponseStatusException;
@Slf4j
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class MyCustomReactiveErrorHandling {
@ExceptionHandler(MyCustomNotFoundException.class)
public void handleMyCustomException(MyCustomNotFoundException ex) {
throw new ResponseStatusException(404, "Data not found!", ex);
}
}
抛出我的异常 returns 其余服务的正确 http 状态代码。