天天看点

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

SpringBoot错误处理机制

  • SpringBoot默认的错误处理机制
  • 原理:ErrorMvcAutoConfiguration(错误处理的自动配置)
    • 处理流程
    • ErrorPageCustomizer
    • BasicErrorController
      • 响应页面errorHtml
      • 响应json数据error
    • DefaultErrorViewResolver
    • DefaultErrorAttributes
  • 定制错误响应
    • 定制错误页面
      • 有模板引擎页面能获取的信息
    • 定制错误的json数据
      • 浏览器和其他客户端都返回json
      • 自适应 :浏览器返回页面,其他返回json
        • MyExceptionHandler 请求转发到/error
        • MyErrorAttributes extends DefaultErrorAttributes 将我们定制的数据携带出去

SpringBoot默认的错误处理机制

当发生错误时,针对不同的客户端,SpringBoot有不同的处理。如果是浏览器,就会返回默认的错误页面;其他客户端,默认响应一个json数据。

区分浏览器和其他客户端的原理:

浏览器发送的请求头的Accept优先接收text/html,

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

而其他客户端发送的请求头的accept并没有指定

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

原理:ErrorMvcAutoConfiguration(错误处理的自动配置)

ErrorMvcAutoConfiguration 给容器中添加了以下组件:

  • DefaultErrorAttributes 在页面共享信息
  • BasicErrorController 处理/error请求
  • ErrorPageCustomizer 定制错误的响应规则:系统出现错误来到error请求进行处理
  • DefaultErrorViewResolver 解析去哪个错误页面

处理流程

一但系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);就会来到/error

请求;就会被BasicErrorController处理;

ErrorPageCustomizer

ErrorPageCustomizer 做的工作就是 来到 /error 请求

ErrorPageCustomizer 定制发生错误后的响应规则,

registerErrorPages方法中会通过getPath()得到 去的路径

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

getPath()的值为/error

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

BasicErrorController

BasicErrorController是用来处理/error请求的,分别针对不同的客户端,产生html类型的数据(errorHtml()方法) 、json数据(error()方法)

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应
【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

BasicErrorController处理/error请求:

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

响应页面errorHtml

通过resolveErrorView方法得到modelAndView,这个modelAndView就是我们返回的错误页面

resolveErrorView方法如下:

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

响应json数据error

DefaultErrorViewResolver

DefaultErrorViewResolver 解析去哪个错误页面,找错误页面的两个地方:

  • 模板引擎

    先去模板引擎找

  • 静态资源

    模板引擎没有就去静态资源下找

    主要就是根据通过error/+错误的状态码 得到viewName 如果模板引擎可以解析这个页面地址就用模板引擎,不能就用resolveResource解析(即在静态资源文件夹下找)

    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应
    resolveResource就是从静态资源中找
    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

DefaultErrorAttributes

BasicErrorController中的errorHtml方法中,传入视图解析器的model 就是通过getErrorAttributes() 方法得到的

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

这个方法最终调用的是ErrorAttributes 的getErrorAttributes() 方法, 而DefaultErrorAttributes就是实现的ErrorAttributes接口

private final ErrorAttributes errorAttributes;
	//---
    protected Map<String, Object> getErrorAttributes(HttpServletRequest request, ErrorAttributeOptions options) {
        WebRequest webRequest = new ServletWebRequest(request);
        return this.errorAttributes.getErrorAttributes(webRequest, options);
    }
           

DefalutErrorAttributes的getErrorAttributes()方法如下:

通过这个方法我们我们就可以知道页面能获取的信息

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

定制错误响应

定制错误页面

根据DefaultErrorViewResolver 视图解析的过程(先再模板引擎中找

error/状态码

,再到静态页面找),

  1. 有模板引擎

    有模板引擎的情况下,我们就在在templates下写error/状态码.html

    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

    我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态

    码.html);

    原因是DefaultErrorViewResolver中放了

    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

有模板引擎页面能获取的信息

timestamp:时间戳

status:状态码

error:错误提示

exception:异常对象

message:异常消息

errors:JSR303数据校验的错误都在这里

原理:

BasicErrorController中的errorHtml方法中,传入视图解析器的model 就是通过getErrorAttributes() 方法得到的,getErrorAttributes() 最终就是调的DefalutErrorAttributes的getErrorAttributes()方法

  1. 没有模板引擎

    没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找;

  2. 以上都没,就默认

    以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面;

定制错误的json数据

浏览器和其他客户端都返回json

我们自己写一个MyExceptionHandler,定制我们想添加的数据后返回json数据

@ControllerAdvice
public class MyExceptionHandler {

    //1. 浏览器和客户端都返回json
    @ResponseBody
    @ExceptionHandler(UserNotExistException.class) //处理UserNotExistException异常
    public Map<String,Object> handleException(Exception e){
        Map<String,Object> map = new HashMap<>();
        map.put("code","user.notexist");
        map.put("message",e.getMessage());
        return map;
    }

           

SpringBoot2 默认对 exception 是关闭的,所以我们要在配置文件中改为true

server.error.include-exception=true
server.error.include-message=always
           

原理:

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应
【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

自适应 :浏览器返回页面,其他返回json

我们想要添加自己的数据后,还是让浏览器返回页面,其他返回json。 那就可以捕获异常后,通过请求转发/error 让BasicErrorController 处理。

我们要添加我们自己的数据,将我们的数据携带出去,就要写自己的MyErrorAttributes继承DefaultErrorAttributes

MyExceptionHandler 请求转发到/error

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

我们可以写一个MyExceptionHandler , 捕获异常后

  1. 将错误状态码改成4xx/5xx (因为BasicErrorController处理的时4xx或5xx错误,我们这种异常的状态码是200)
    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应
    【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应
    可以看到BasicErrorController的状态码是通过

    request.getAttribute("javax.servlet.error.status_code")

    得到的,因此我们可以如下设置状态码:
  2. 添加我们的数据,放到request域中,让MyErrorAttributes可以获取到把这些数据传出去
    map.put("code","user.notexist");
        map.put("message",e.getMessage());
        request.setAttribute("ext",map); //将我们的数据放到request域中
               
  3. 转发到/error 请求(因为BasicErrorController就是处理/error请求的)

MyErrorAttributes extends DefaultErrorAttributes 将我们定制的数据携带出去

出现错误以后,会来到/error请求,会被BasicErrorController处理。

而我们在MyExceptionHandler中添加的自己的数据,BasicErrorController并不知道,通过查看BasicErrorController源码,我们可以看到

响应出去可以获取的数据是由

getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);

页面上能用的数据,或者是json返回能用的数据都是通过DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的

因此我们可以通过继承DefaultErrorAttributes ,写一个我们的MyErrorAttributes 把我们的数据携带出去

【SpringBoot】错误处理机制SpringBoot默认的错误处理机制原理:ErrorMvcAutoConfiguration(错误处理的自动配置)定制错误响应

继续阅读