一、背景
系統定義了全局統一異常處理,使用了@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 中的回答