一. SpringBoot的默认错误处理策略

1. 对404的默认处理策略

我们在发送请求的时候,如果发生了404异常,SpringBoot是怎么处理的呢?

我们可以随便发送一个不存在的请求来验证一下,就会看到如下图所示:

2. 对500的默认处理策略

当服务器内部发生代码等错误的时候,会发生什么呢?

比如我们人为的制造一个异常出来,如下面的代码所示:

@GetMapping("/user/{id:d+}")public User get(@PathVariable String id) {    throw new RuntimeException();}

结果产生了如下所示效果图:

3.在error页面中可以获取的错误信息

timestamp: 时间戳.status: 状态码.error: 错误提示.exception: 异常对象.message: 异常消息.errors: 数据效验相关的信息.

二. Spring Boot错误处理机制探究

通过上面的两个案例,我们发现无论发生了什么错误,Spring Boot都会返回一个对应的状态码以及一个错误页面,那么这个错误页面是怎么来的呢?

要弄明白这个问题,我们需要从Spring Boot中错误处理的底层源码来进行分析。

1. SpringBoot的错误配置信息

SpringBoot的错误配置信息是通过ErrorMvcAutoConfiguration这个类来进行配置的,这个类中帮我们注册了以下组件:

DefaultErrorAttributes: 帮我们在页面上共享错误信息;ErrorPageCustomizer: 项目中发生错误后,该对象就会生效,用来定义请求规则;BasicErrorController: 处理默认的 ’/error‘ 请求,分为两种处理请求方式:一种是html方式,一种是json方式;DefaultErrorViewResolver: 默认的错误视图解析器,将错误信息解析到相应的错误视图.

2. Spring Boot处理error的流程

  • 一旦系统中出现 4xx 或者 5xx 之类的错误, ErrorPageCustomizer就会生效(定义错误的相应规则);
  • 然后内部的过滤器就会映射到 ’/error‘ 请求,接着该/error请求就会被BasicErrorController处理;
  • 然后BasicErrorController会根据请求中的Accept来区分该请求是浏览器发来的,还是由其它客户端工具发来的.此时一般分为两种处理方式:errorHtml()和error().
  • 在errorHtml()方法中,获取错误状态信息,由resolveErrorView解析器解析到默认的错误视图页面,默认的错误页面是/error/404.html页面;
  • 而如果templates目录中的error目录里面有这个页面,404错误就会精确匹配404.html;
  • 如果没有这个404.html页面它就会模糊匹配4xx.html页面;
  • 如果templates中没有找到错误页面,它就会去static文件中找.

注:

static文件夹存放的是静态页面,它没有办法使用模板引擎表达式.

简单概括就是:

1️⃣. 当出现4xx或5xx的错误:ErrorPageCustomizer开始生效;

2️⃣. 然后ErrorPageCustomizer发起 /error 请求;

3️⃣. /error 请求被BasicErrorController处理;

4️⃣. BasicErrorController根据请求头中的Accept决定如何响应处理.

其实在以上的所有类中,最重要的一个类就是BasicErrorController,所以接下来我们来分析BasicErrorController源码,看看Spring Boot底层到底是怎么实现error处理的。

三. BasicErrorController源码详解

在Spring Boot中,当发生了错误后,默认情况下,Spring Boot提供了一个处理程序出错的结果映射路径 /error。当发生错误后,Spring Boot就会将请求转发到BasicErrorController控制器来处理这个错误请求。

1. BasicErrorController源码

所以我们重点分析BasicErrorController源码,首先呈上源码内容:

@Controller@RequestMapping("${server.error.path:${error.path:/error}}")public class BasicErrorController extends AbstractErrorController {    private final ErrorProperties errorProperties;    /**     * Create a new {@link BasicErrorController} instance.     * @param errorAttributes the error attributes     * @param errorProperties configuration properties     */    public BasicErrorController(ErrorAttributes errorAttributes,            ErrorProperties errorProperties) {        this(errorAttributes, errorProperties,                Collections.emptyList());    }    /**     * Create a new {@link BasicErrorController} instance.     * @param errorAttributes the error attributes     * @param errorProperties configuration properties     * @param errorViewResolvers error view resolvers     */    public BasicErrorController(ErrorAttributes errorAttributes,            ErrorProperties errorProperties, List errorViewResolvers) {        super(errorAttributes, errorViewResolvers);        Assert.notNull(errorProperties, "ErrorProperties must not be null");        this.errorProperties = errorProperties;    }    @Override    public String getErrorPath() {        return this.errorProperties.getPath();    }    @RequestMapping(produces = "text/html")    public ModelAndView errorHtml(HttpServletRequest request,            HttpServletResponse response) {        HttpStatus status = getStatus(request);        Map model = Collections.unmodifiableMap(getErrorAttributes(                request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));        response.setStatus(status.value());        ModelAndView modelAndView = resolveErrorView(request, response, status, model);        return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);    }    @RequestMapping    @ResponseBody    public ResponseEntity> error(HttpServletRequest request) {        Map body = getErrorAttributes(request,                isIncludeStackTrace(request, MediaType.ALL));        HttpStatus status = getStatus(request);        return new ResponseEntity>(body, status);}

2. error.path分析

这个源码的注释信息中说明了,这是一个Spring Boot自带的全局错误Controller.

这个Controller中有一个RequestMapping注解,内部有一个相当于三元运算符的操作。如果你在配置文件配置了server.error.path的话,就会使用你配置的异常处理地址,如果没有就会使用你配置的error.path路径地址,如果还是没有,则默认使用/error来作为发生异常时的处理地址。

所以我们可以按照如下图中的配置,来设置自定义的错误处理页面。

3. errorHtml()与error()方法解析

从上面的源码我们可以看到,BasicErrorController中有两个RequestMapping方法,分别是errorHtml()与error()方法来处理错误请求。

那么为什么会是两个呢?请看下面的截图:

BasicErrorController内部是通过读取request请求头中的Accept属性值,判断其内容是否为text/html;然后以此来区分请求到底是来自于浏览器(浏览器通常默认自动发送请求头内容Accept:text/html),还是客户端,从而决定是返回一个页面视图,还是返回一个 JSON 消息内容。

可以看到其中errorHtml()方法是用来处理浏览器发送来的请求,它会产生一个白色标签样式(whitelabel)的错误视图页面,该视图将以HTML格式渲染出错误数据。

该方法返回了一个error页面,如果你的项目静态页面下刚好存在一个error所对应的页面,那么Spring Boot会得到你本地的页面,如下图:

而error()方法用来处理来自非浏览器,也就是其他软件app客户端(比如postman等)发送来的错误请求,它会产生一个包含详细错误,HTTP状态及其他异常信息的JSON格式的响应内容。

注:

BasicErrorController可以作为自定义ErrorController的基类,我们只需要继承BasicErrorController,添加一个public方法,并添加@RequestMapping注解,让该注解带有produces属性,然后创建出该新类型的bean即可。

4. /error映射默认处理策略总结

经过上面的源码分析得知,在默认情况下,Spring Boot为这两种情况提供了不同的响应方式.

4.1 响应'Whitelabel Error Page'页面

一种是浏览器客户端请求一个不存在的页面或服务端处理发生异常时,这时候一般Spring Boot默认会响应一个html文档内容,称作“Whitelabel Error Page”:

4.2 响应JSON字符串

另一种是当我们使用Postman等调试工具发送请求一个不存在的url或服务端处理发生异常时,Spring Boot会返回类似如下的一个 JSON 字符串信息:

{    "timestamp": "2019-05-20T06:12:45.209+0000",    "status": 404,    "error": "Not Found",    "message": "No message available",    "path": "/login.html"}

html页面源码_整合SpringMVC之错误处理底层原理及源码分析相关推荐

  1. 开源项目实例源码_今年我读了四个开源项目的源码,来分享下心得

    今年来看了 RocketMQ.Kafka.Dubbo .Tomcat 的源码,之前也有读者询问过如何读源码,索性就来分享一下. 其实还看了一点点 Linux.Redis.jdk8,这几个阅读的目的和上 ...

  2. app商城源码_海量的SpringBoot和SSM项目【附带源码+视频教程】快速成为全栈

    为了帮助更多的小伙伴进行项目的锻炼,孟哥整理较多的实战项目,包括SSM.Springboot.Springcloud.小程序等. 各种项目还在不断的更新中--仅限制学习使用,若有侵权,请联系删除. 点 ...

  3. 生鲜配送小程序源码_生鲜社区团购配送系统小程序源码搭建平台模式

    生鲜配送系统开发,找[金生157威6875店2419同号]生鲜配送模式开发,生鲜配送软件开发,生鲜配送APP开发,生鲜配送平台开发平台,生鲜配送系统源码开发平台,生鲜配送系统平台,生鲜配送系统定制开发 ...

  4. vim ctags java源码_如何使用vim的插件Ctags查看Linux源码

    一.ubuntu下安装Linux内核源码 (1).查看自己的内核版本 (2).查看源内的内核源码类表 (3).下载源码 (4).进入/usr/src (5).解压下载的文件到用户主 二.安装vim插件 ...

  5. onclick 源码_精读:手写React框架 解析Hooks源码

    写在开头: 去年发表过一篇手写React,带diff算法,异步setState队列的文章,有一位阿里的朋友在下面评论,让我可以用hooks实现一次,也很简单,我当时觉得,这人有病,现在回过头来看,还是 ...

  6. java.lang.object源码_第三篇:java.lang.Object 类源码分析

    Object所包含的方法如下: ① public Object(); 构造函数: 大部分情况下,类对象的声明,都是通过构造函数完成的(Java中规定:在类定义过程中,对于未定义构造函数的类,默认会有一 ...

  7. java的jdbc看不到源码_不了解jdbc,何谈Mybatis的源码解析?

    这篇文章主要用来展示jdbc的使用,是为了方便阅读MyBatis源码使用的,为源码分析做一个提前热身: 里面很多关键性的信息在MyBatis源码里面都能找到,本篇不做MyBatis源码的分析, 因为M ...

  8. 补单平台开发搭建源码_补单系统开发搭建IDEA导入jdk8源码学习(报错解决方案)

    补单系统功能介绍 一.买家端 1.本套系统可以获取客户通讯录,方式买家跑单骗单: 2.任务大厅:买家可以在任务大厅选择自己觉得佣金和平台适合自己的订单操作: 3.已接任务:可以查看我们所接的订单,以及 ...

  9. 微信签到抽奖程序java源码_某宝买的微信抽奖签到墙源码,年会,学习源码--已经配置完成了,源码没问题,可直接用...

    本帖最后由 没有星星的夜空 于 2020-1-6 15:46 编辑 老铁门都要18办内定的,那行,已经更新到蓝揍链接了,打开连接后看备注问题1.浏览器版本不兼容问题,在首页文件里面把注释去掉就好了 问 ...

最新文章

  1. R符号秩检验(WILCOXON SIGNED RANK TEST)
  2. beanutils工具类_Apache Commons 工具类介绍及简单使用
  3. 用 JavaScript 操作字符串
  4. HTML+CSS+JS实现 ❤️鼠标悬停性感美女图片特效❤️
  5. 安装JDK 9与使用jshell
  6. 对python语言的认识_认识Python语言和基础知识
  7. 经典Hello Word窗口表示,可视化编程入门。
  8. GPS 相关知识科普
  9. 海湾火灾自动报警系统中文编码查询表
  10. 照片放大不清晰怎么处理?用嗨格式图片无损放大器
  11. 愿为双鸿鹄,奋翅起高飞
  12. win2008服务器系统玩红警,win8系统玩不了红色警戒2如何解决?win8系统玩不了红色警戒2解决方法...
  13. c语言看门狗指令pic,PIC单片机之看门狗_看门狗定时器工作原理
  14. Qt 网络聊天室项目
  15. 用Hadoop构建电影推荐系统
  16. python 神经网络预测未来30天数据_使用LSTM循环神经网络的时间序列预测实例:预测未来的货币汇率...
  17. 小米6刷Android10以及Xposed
  18. Tkinter定时刷新页面或数据
  19. 来篇鸡汤文吧,教你如何七周内从小菜鸟成长为一名合格的数据分析师
  20. 数据类型、变量、字符串(工匠工坊第二课)

热门文章

  1. allegropcb怎么导出成cad_私藏技巧分享!CAD中的表格坐标快速输出成Excel!
  2. mysql ansi_ANSI模式下如何运行MySQL
  3. 被VS Code牢牢圈粉了!
  4. 属实逼真,决策树可视化!
  5. 腾讯和阿里在B站“打起来了”,你何时见过这场面?
  6. 给大家推荐认识一位中科院大佬!
  7. 贵州瑶山古寨旅游产品设计_快领取!贵州推出20条秋冬旅游线路
  8. 深度学习-Tensorflow2.2-深度学习基础和tf.keras{1}-优化函数,学习速率,反向传播,网络优化与超参数选择,Dropout 抑制过拟合概述-07
  9. 09-百度ai图片识别
  10. 一句话理解tf.identity的含义