全局异常处理
原先的全剧异常处理没有对response的status进行设置。导致虽然是返回体抛出了错误的code码。但是Http Status还是200的状态。
原有逻辑如下:
@ExceptionHandler(Exception.class)
@ResponseBody
public ResultVO defaultExceptionHandler(Exception e){
log.error("异常,{}", e.getMessage(), e);
if(e instanceof BusinessException) {
BusinessException businessException = (BusinessException)e;
if (businessException.getCode().intValue() == 90001){
//90001异常编号返回成功,提交定单
Map<String, Object> m = new HashMap<>();
m.put("type", 2);
m.put("msg", businessException.getMessage());
return ResultUtils.success(m);
}
return ResultUtils.error(businessException.getCode(), businessException.getMessage());
}
// ...
}上面的代码,对返回的请求异常进行捕获,并写入了一个统一包装的ResultVO中。
注入的code与msg内容皆为异常抛出的code与msg。
但在实际的返回给上游服务或者是前端时。HTTP Status 始终是200。从请求状态来看始终是没有异常的
改变后如下:
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(AccessDeniedException.class)
public ResultVO<?> accessDeniedExceptionHandler(AccessDeniedException e) {
log.error("授权异常: {}", e.getMessage(), e);
return ResultUtils.error(ResultEnum.UNAUTHORIZED.getCode(), e.getMessage());
}当我需要对认证异常进行捕获并统一封装时,我可以像上面这么写,并且指定返回的Http Status为401
异常的捕获处理完成,并返回ResultVO之后,在上游服务或者是Http 请求显示的状态就为401
并且可以定义多个这样的处理,如下:
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler({ServiceException.class, BusinessException.class})
public ResultVO<?> throwableHandler(Throwable ex) {
log.error("业务异常: {}", ex.getMessage(), ex);
if (ex instanceof ServiceException serviceException) {
return ResultUtils.error(serviceException.getCode(), serviceException.getMessage());
}
if (ex instanceof BusinessException businessException) {
return ResultUtils.error(businessException.getCode(), businessException.getMessage());
}
return ResultUtils.error(ex.getMessage());
}在@ExceptionHandler中指定多个需要抓取的异常进行处理。
并使用@ResponseStatus()这个注解对当前异常需要返回的Http Status Code进行定义
详细的Http Status Code可以参考Spring中的下面这个类
org.springframework.http.HttpStatus
如此一来,当我需要对OpenFeign远程调用进行异常传递的时候,就可以进行处理
OpenFeign 异常处理
原有逻辑的Exception Handler虽然捕获了异常并封装了。但是实际的Http Status始终是200。
当自定义实现Feign的ErrorDecoder接口时,并不会捕获到异常。
如果我们在全局异常捕获处理中,对异常的状态捕获完成之后,并给定了非200的状态,自定义的Feign异常解码就会生效
@Slf4j
@Configuration
public class FeignErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
String url = response.request().url();
if (response.status() == 404) {
return new BusinessException("远程服务接口不存在:" + url);
}
try {
String errorContent = Util.toString(response.body().asReader());
log.error("调用远程:{}异常, errorContent:{}", url, errorContent);
ResultVO resultVO = JSONUtils.string2Obj(errorContent, ResultVO.class);
throw new BusinessException(resultVO.getMsg());
} catch (IOException e) {
log.error("处理 FeignClient 异常错误", e);
return new RuntimeException("处理FeignClient 异常错误");
}
}
}