spring-boot2(二十四)在配置全局异常的时候404不生效解决方案

分类: spring-boot
阅读:571
作者:majingjing
发布:2019-11-28 17:58:14

在使用spring-boot2开发微服务的时候, 如果系统出现错误是就需要提供一套统一的响应码
比如:

{
    "error_code": 50001,
    "error_message": "No handler found for GET /api/xxx",
    "error_data": null
}

常规的配置很简单,如下

@RestControllerAdvice
@Slf4j
public class ExceptionHandlerAdvice
      //  extends ResponseEntityExceptionHandler
{

    // @Override
    // protected ResponseEntity<Object> handleNoHandlerFoundException(
    //         NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    //     log.error("Exception", ex);
    //     //return handleExceptionInternal(ex, null, headers, status, request);
    //     return ResponseEntity.status(400).body(new ErrorResponse(ApiErrorCode.NO_4_00_02.getErrorCode(), ex.getMessage()));
    //
    // }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<Object> Exception(Exception e) {
        log.error("Exception", e);
        return ResponseEntity.status(500).body(new ErrorResponse(ApiErrorCode.NO_5_00_01.getErrorCode(),e.getMessage()));
    }

    @ExceptionHandler(ApiException.class)
    @ResponseBody
    public ResponseEntity<Object> ApiException(ApiException e) {
        log.error("ApiException", e);
        return ResponseEntity.status(400).body(new ErrorResponse(e.getErrorCode(), e.getErrorMessage(), e.getErrorData()));
    }

    @ExceptionHandler(ValidationException.class)
    @ResponseBody
    public ResponseEntity<Object> ValidationException(ValidationException e) {
        log.error("ValidationException", e);
        return ResponseEntity.status(400).body(new ErrorResponse(ApiErrorCode.NO_4_00_01.getErrorCode(),e.getMessage()));
    }

}

如上很简单的就实现了异常的统一处理,可以返回上述的json格式数据

但是当我们访问一个没有的资源时,并没有按照我们的预期进入ExceptionHandlerAdvice 比如我们访问: /api/xxx1 此时这个资源是不存在的,响应内容如下

{
    "timestamp": "2019-11-28 17:47:07",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/api/xxx1"
}

很明显并没有按照我们的数据格式输出

这究竟是什么原因导致404的时候不走我们的 ExceptionHandlerAdvice 呢 ? 经过一番源代码的解读, 我们就很容易发现根本原因
源代码类文件 org.springframework.web.servlet.doDispatch(HttpServletRequest request, HttpServletResponse response) 这也是所有请求的入口

从上面代码可以看到, 程序并没有抛出异常,而是直接返回了

问题的根本原因找到了, 就很容易了, 我们直接在配置中将这个值设置为throwExceptionIfNoHandlerFound = true即可

spring:
  mvc:
    throw-exception-if-no-handler-found: true

再次启动程序验证,即可验证此时已经进入到我们定义的 ExceptionHandlerAdvice中, 可以自定义封装,返回我们想要的数据格式

细心的同学想必也看到了, 上面的ExceptionHandlerAdvice我注释了一段代码 // extends ResponseEntityExceptionHandler 有兴趣的可以深入阅读下这个类 , 可以发现框架已经帮我们封装好了各种异常的处理, 我们可以采用继承的方式来简化处理, 如果需要自定义,只需重写对应的handle方法


番外篇: 如果是有静态资源的访问如果想排除这个异常的拦截(减少系统无效的并发压力),也是可以配置的

spring:
  mvc:
    throw-exception-if-no-handler-found: true
  resources:
    add-mappings: false