springboot的错误处理机制(源码解析)
在 ErrorMvcAutoConfiguration类中注册了许多错误处理类。
- ErrorPageCustomizer 错误页面定制器
- BasicErrorController 错误页面处器
- DefaultErrorViewResolver 默认错误视图处理器
ErrorPageCustomizer类中有一个方法registerErrorPages()获取了错误路径。
获取的路径为/error。当出现错误时,errorPageCustomizer就会生效,并来到/error请求,由BasicErrorController来处理
BasicErrorController类处理错误请求,处理规则为先根据server.error.path,再根据error.path,最后为 /error
BasicErrorController类会根据请求头中的信息处理请求。
如果是浏览器发出的请求,则会返回html页面,否则一般返回json数据
进入该方法
发现resolveErrorView()方法是接口ErrorViewResolver接口中的抽象方法,它调用的应该是该接口的实现类中的resolveErrorView()方法,所以我们应该找该接口的实现类中的resolveErrorView()方法
找到给ErrorViewResolver接口的唯一实现类 -> DefaultErrorViewResolver
找到该类中的resolveErrorView()方法,发现该方法又调用了resolve()方法来处并返回视图对象,并将错误状态码String.valueOf(status.value())作为参数传过去
resolve()方法中,视图名为 “error/”+状态码(请记住这里,下面会用到) 。并判断是否存在模板引擎。
如果存在模板引擎,则由模板引擎处理,返回"error/"+状态码视图对象。
如果不存在模板引擎,则调用resolveResource()方法处理视图
如果不存在模板引擎,进入resolveResource()方法。通过for循环遍历静态资源的地址,viewName与.html拼接,判断view.html文件是否存在。如果存在,则返回视图对象,否则返回null。所以我们要知道location是什么。
上一个方法中通过调用this.resourceProperties.getStaticLocations()方法来获取静态资源的位置,我们再进入该方法
静态资源文件夹:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
所以我们的静态资源可以放在这四个文件夹下。(我们可以自己新建这些文件夹来存放文件)。
最后我们遍历这四个文件夹,看这四个文件夹下是否存在 view.html 文件。如果存在则返回该视图,否则返回null。
我们再回到DefaultErrorViewResolver类中的**resolve()**方法
它的返回值有两种结果:
1.
存在模板引擎,返回errorViewName 视图
不存在模板引擎,但那四个静态资源文件下存在errorViewName .html文件,返回errorViewName 视图
2.
不存在模板引擎,四个静态资源文件下不存在errorViewName.html文件,返回null。
结果为返回 errorViewName 视图对象 或 null
我们再回到BasicErrorController类中的errorHtml()方法
根据前面的返回值,若返回值不为null,则返回errorViewName 视图对象(也就是"error/"+状态码+.html, 如:error/404.html)。若返回值为null,则返回error.html视图对象(也就是我们默认的错误页面)
到这里我们就知道了自定义具体的错误页面了。
我们可以在那四个静态资源文件夹或模板引擎处理的文件夹templates下新建一个error文件夹,在该文件夹下新建具体的状态码.html文件,如 404.html,500.html 来显示具体的错误页面。不过错误代码有很多,我们又不想新建太多的具体的状态码.html文件,那么我们应该怎么做呢?
从前面我们已经可以知道DefaultErrorViewResolver是一个错误视图处理类,我们再进入该类。可以看到该类中有一个静态代码块,将 4xx与5xx存入了views,并最终将结果存入了SERIES_VIEWS中,接下来我们再看一下SERIES_VIEWS在哪里被处理了。
很高兴的又回到了resolveErrorView()方法,同上面所讲的,我们可以知道,最终的错误页面名应该为 4xx.html 或 5xx.html,所以我们可以在error文件夹下新建4xx.html 或 5xx.html 来处理 状态码为以4开头或以5开头的错误。
总结:
- 当出现错误时,ErrorPageCustomizer就会生效,并来到/error请求,由BasicErrorController来处理
- BasicErrorController 为错误处理器,处理错误
- DefaultErrorViewResolver 为视图处理器,将错误视图解析并交给BasicErrorController转发到错误页面
- 自定义错误页面
4.1 error文件夹放在模板文件夹templates下(发生错误时优先在该文件夹找)
4.2 error文件夹放在四个静态资源文件夹下
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/ - 命名.html文件
5.1 具体的状态码
404.html
500.html
5.2 非具体的状态码
4xx.html
5xx.html
6.如果有具体状态码的错误页面,则显示具体状态码的错误页面,否则显示非具体的状态码的错误页面
因为这篇文章已经很长了,想看错误页面定制的朋友可以看下我这篇文章
https://blog.csdn.net/weixin_45359574/article/details/107258597