【SpringBoot】错误处理机制

SpringBoot默认的错误处理机制

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

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

浏览器发送的请求头的Accept优先接收text/html,
在这里插入图片描述

而其他客户端发送的请求头的accept并没有指定
在这里插入图片描述

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

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

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

处理流程

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

ErrorPageCustomizer

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

ErrorPageCustomizer 定制发生错误后的响应规则,
registerErrorPages方法中会通过getPath()得到 去的路径在这里插入图片描述
getPath()的值为/error
在这里插入图片描述

BasicErrorController

BasicErrorController是用来处理/error请求的,分别针对不同的客户端,产生html类型的数据(errorHtml()方法) 、json数据(error()方法)
在这里插入图片描述
在这里插入图片描述
BasicErrorController处理/error请求:
在这里插入图片描述

响应页面errorHtml

通过resolveErrorView方法得到modelAndView,这个modelAndView就是我们返回的错误页面
resolveErrorView方法如下:
在这里插入图片描述

响应json数据error

DefaultErrorViewResolver

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

  • 模板引擎
    先去模板引擎找
  • 静态资源
    模板引擎没有就去静态资源下找
    主要就是根据通过error/+错误的状态码 得到viewName 如果模板引擎可以解析这个页面地址就用模板引擎,不能就用resolveResource解析(即在静态资源文件夹下找)
    在这里插入图片描述
    resolveResource就是从静态资源中找
    在这里插入图片描述

DefaultErrorAttributes

BasicErrorController中的errorHtml方法中,传入视图解析器的model 就是通过getErrorAttributes() 方法得到的
在这里插入图片描述

这个方法最终调用的是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()方法如下:
通过这个方法我们我们就可以知道页面能获取的信息
在这里插入图片描述

定制错误响应

定制错误页面

根据DefaultErrorViewResolver 视图解析的过程(先再模板引擎中找error/状态码,再到静态页面找),

  1. 有模板引擎
    有模板引擎的情况下,我们就在在templates下写error/状态码.html
    在这里插入图片描述
    我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态
    码.html);
    原因是DefaultErrorViewResolver中放了
    在这里插入图片描述

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

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

原理:

在这里插入图片描述

在这里插入图片描述

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

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

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

MyExceptionHandler 请求转发到/error

在这里插入图片描述

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

  1. 将错误状态码改成4xx/5xx (因为BasicErrorController处理的时4xx或5xx错误,我们这种异常的状态码是200)
    在这里插入图片描述
    在这里插入图片描述

    可以看到BasicErrorController的状态码是通过request.getAttribute("javax.servlet.error.status_code")得到的,因此我们可以如下设置状态码:

     request.setAttribute("javax.servlet.error.status_code",500);
    
  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 把我们的数据携带出去

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值