Spring Boot 全局异常捕获 ControllerAdvice 无法捕获 过滤器(Filter)和拦截器(Interceptor)中的异常

Spring Boot 全局异常捕获 ControllerAdvice 无法捕获 过滤器(Filter)和拦截器(Interceptor)中的异常

💡 原文中文,约1900字,阅读约需5分钟。
📝

内容提要

在Spring Boot中,@RestControllerAdvice和@ControllerAdvice用于全局捕获异常,但无法捕获过滤器中抛出的异常。要捕获过滤器中的异常,需要在过滤器中将异常传递到后续处理的Controller。示例代码展示了如何在过滤器中捕获ExpiredJwtException,并通过Dispatcher转发到特定Controller,以便ControllerAdvice能够处理该异常。

🔎

延伸解读

为什么过滤器异常无法被全局捕获

Spring Boot 中,请求处理链的顺序是过滤器 -> 拦截器 -> ControllerAdvice。ControllerAdvice 位于 Controller 层之后,因此当过滤器或拦截器中抛出异常时,请求尚未到达 ControllerAdvice 的处理范围,异常自然无法被其捕获。只有 Controller、Service、DAO 层抛出的异常才能被 ControllerAdvice 拦截。理解这一执行顺序是解决问题的关键。

将过滤器异常转发到 Controller 的处理思路

文章给出的方案是在过滤器中捕获异常后,不直接抛出,而是将异常对象存入 request 属性,并通过 RequestDispatcher 转发到一个专门接收异常的 Controller。该 Controller 从属性中取出异常并重新抛出,此时异常已进入 Controller 层,ControllerAdvice 便能正常捕获并处理。这种方法利用了转发机制,将异常处理时机后移。

实现时的注意事项与潜在局限

使用转发方案时,需确保转发路径对应的 Controller 能正确接收请求,并注意转发可能改变请求路径或引发二次过滤。此外,该方案仅适用于过滤器内部可捕获的异常,若异常发生在转发过程中,仍可能无法被 ControllerAdvice 处理。文章未讨论性能影响或替代方案,实际使用时需结合项目情况评估。

❓

Q&A

在Spring Boot中,如何使用@ControllerAdvice捕获异常?

可以使用@RestControllerAdvice和@ControllerAdvice来全局捕获异常,但它们无法捕获过滤器中抛出的异常。

为什么@ControllerAdvice无法捕获过滤器中的异常?

因为过滤器的执行顺序是过滤器->拦截器->ControllerAdvice,过滤器中抛出的异常在ControllerAdvice执行之前就已经停止了执行。

如何在过滤器中处理ExpiredJwtException异常?

在过滤器中捕获ExpiredJwtException后,可以将异常对象设置到请求属性中,并通过Dispatcher转发到特定的Controller。

在过滤器中捕获异常后,如何将其传递给Controller?

可以通过设置请求属性并使用Dispatcher转发到一个接收异常的Controller来传递异常。

如何实现一个接收异常的Controller?

可以创建一个Controller,使用@RequestMapping注解定义一个路径,并在该路径的方法中从请求属性中取出异常并重新抛出。

如何使用@RestControllerAdvice处理ExpiredJwtException?

可以在@RestControllerAdvice中定义一个@ExceptionHandler方法,专门处理ExpiredJwtException并返回相应的ApiResult。

🏷️

标签

➡️

继续阅读