Spring Filter 全局异常处理器
在之前的 Spring-Validation 中简单介绍了如何通过 @RestControllerAdvice
或者 @ControllerAdvice
注解来处理全局异常,但是这种方式只能 处理 Controller
层抛出的异常。
这篇文章介绍如何处理自定义 Filter
抛出的异常。
自定义 Filter
例如我们可能需要一个 Filter
来检验 Token
是否合法,而检查的过程中发现 Token
不合法,则抛出异常。
@WebFilter
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// ignore non business api and some special api
if (!request.getRequestURI().startsWith(ApiPathConstant.ALL_API_PREFIX) ||
ignorePath.contains(request.getRequestURI())) {
filterChain.doFilter(request, response);
return;
}
// throw exception if authorization failed
authorize(request, request.getHeader("Token"));
filterChain.doFilter(request, response);
}
}
注意:通过 @WebFilter
注释的 Filter
需要在 @SpringBootApplication
启动类中添加 @ServletComponentScan("xxx.xxx.xx")
注解指定 Filter
的查找路径。
上面过程中抛出的异常不会被 @RestControllerAdvice
或者 @ControllerAdvice
捕获。
HandlerExceptionResolver
实际上 Spring Boot
的异常处理是通过 HandlerExceptionResolver
来实现的。Spring Boot
中已经存在 两个默认的 HandlerExceptionResolver
,我们可以通过 @Qualifier("HandlerExceptionResolver")
配合 @Autowired
获取到负责处理异常的 HandlerExceptionResolver
,然后显式调用 resolveException
方法来处理异常。
解决方案
要实现这些,我们只需要自定义一个 Filter
并让其第一个执行,对捕获到的异常显式调用 resolveException
进行处理就可以触发全局定义的异常处理器:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionHandlerFiter extends OncePerRequestFilter {
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (Exception e) {
resolver.resolveException(request, response, null, e);
}
}
}
注意:@WebFilter
不能指定 Filter
的执行顺序 (实际上是可以的,通过指定 @WebFilter
中的 filterName
,执行顺序是按照该字段的字典序),要指定 Filter
的执行顺序,我们可以通 @Order
和 @Component
来实现,@Order
的值越小,执行顺序越靠前,上述例子的 Ordered.HIGHEST_PRECEDENCE
实际上是 Integer.MIN_VALUE
。
resolveException
会自动根据异常的类型找到对应的异常处理器进行处理。这样,我们就可以处理 Filter
抛出的异常了:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(JwtException.class)
public ErrorVO handleJwtException(JwtException e, HttpServletRequest request) {
logger.error("Invalid Token from {}", request.getRemoteAddr());
return new ErrorVO(ErrorMessageConstant.INVALID_TOKEN);
}
}
Enjoy Reading This Article?
Here are some more articles you might like to read next: