一、背景
系统定义了全局统一异常处理,使用了@RestControllerAdvice注解的方式。
@Slf4j
@RestControllerAdvice
@SuppressWarnings("unchecked")
public class GlobalExceptionHandlerAdvice {
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
public BaseResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("MethodArgumentNotValidException:" + e.getMessage());
FieldError fe = (FieldError) e.getBindingResult().getAllErrors().get(0);
String message = String.format("%s %s", fe.getField(), StringUtils.isNotBlank(fe.getDefaultMessage()) ? fe.getDefaultMessage() : e.getMessage());
return BaseResponse.with(Code.PARAM_ERROR.getCode(), message);
}
@ExceptionHandler(JwtException.class)
public BaseResponse handleJwtException(JwtException e) {
log.error(e.getMessage(), e);
return BaseResponse.with(Code.UN_AUTHORIZATION);
}
@ExceptionHandler(Exception.class)
public ResponseEntity handleException(Exception e) {
log.error(e.getMessage(), e);
return new ResponseEntity(BaseResponse.with(Code.SYSTEM_ERROR.getCode(), Code.SYSTEM_ERROR.getMsg()
+ " " + e.getClass().getName() + ":" + e.getMessage(), null), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
鉴权使用的是JWT,使用filter对token进行解析和验证。然后突然发现一个问题,就是当token过期时,抛出的异常无法通过全局统一异常处理对外返回,而是返回500。
二、原因
全局统一异常处理只能处理控制器中发生的异常。要在Spring Security过滤器链中重用此功能,需要定义过滤器并将其挂钩到安全配置中。过滤器需要将异常重定向到统一异常处理中。
三、代码
在filter中注入HandlerExceptionResolver
@Autowired
@Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
然后在catch中抛出
catch (Exception e) {
e.printStackTrace();
resolver.resolveException(request, response, null, e);
}
之后在GlobalExceptionHandlerAdvice中定义需要处理的异常类型,本文中用的是JwtException
@ExceptionHandler(JwtException.class)
public BaseResponse handleJwtException(JwtException e) {
log.error(e.getMessage(), e);
return BaseResponse.with(Code.UN_AUTHORIZATION);
}
这时便可以跟在业务代码里面抛出的业务异常一样处理了。
四、备注
参考了https://stackoverflow.com/questions/34595605/how-to-manage-exceptions-thrown-in-filters-in-spring 中的回答