其实web服务器是会处理错误的

在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生。

根据错误代码处理错误,如下图01:

根据异常类型处理错误,如下图02:

不过我们更加熟悉的应该是SpringMVC的统一异常处理。如下图03:

看到@ControllerAdvice注解和@ExceptionHandler注解都应该很熟悉吧。

处理原理就是在捕获到业务Controller有异常抛出时,根据异常类型来这里找到对应的方法并执行。

可见,整个异常的处理过程都是在SpringMVC内部给搞定了,根本就没有涉及到web服务器,如tomcat。

那么问题来了,明明web服务器可以处理异常,为啥SpringMVC还要自己处理呢?

是不想呢,还是另有苦衷

读过本系列上一篇文章的小伙伴应该能猜出来一些。因为SpringMVC开发的工程最终打成war包,然后扔到tomcat下面即可。

而且SpringMVC和tomcat之间是通过Java Web的规范联系起来的,它们之间根本没有办法自由交互的。

然而tomcat的错误处理需要在web.xml里面配置。严格来说,web.xml其实和SpringMVC关系不大。

特别是Spring全面进入Java和注解配置时代以后,web.xml逐渐被弱化,继而变得可有可无,直到最终完全消失。

所以(我猜测)SpringMVC可能不希望自己的用户到一个和自己关系不大的web.xml里面配置一些和业务相关的异常处理映射。

所以只好自己把异常处理消化掉。不劳tomcat大驾。因此才有了SpringMVC统一处理异常。

重新让web服务器来处理错误

当历史来到了SpringBoot的时代,SpringBoot翻身做主成了入口,web服务器竟然成了一个组件。

SpringBoot可以操作web服务器的API,通过编程的方式,对web服务器进行深度配置。

所以很多事情都变得容易起来,比如错误处理。

因为web.xml里的错误处理映射最终是注册到tomcat里面了,所以SpringBoot只要操作tomcat的API,使用编程的方式也来注册一些错误处理映射不就可以了嘛。

因为用户直接是和SpringBoot打交道的,所以SpringBoot需要抽象出一套错误处理注册机制,让用户来注册。

这样SpringBoot拿到用户注册的错误处理映射信息后,在生成web服务器(如tomcat)时,把这些映射信息添加到web服务器中即可。

SpringBoot注册错误处理映射的方案

先来看看错误处理映射是如何描述的,如下图04:

三个字段的含义是:

path是一个路径,它表示的是错误处理的url。

status是一个状态码,如404、500等。

exception是一个异常类型,如LoginFailedException。

一共有三种使用方式:

1)status + path,如404 + /404,表示如果遇到了404,就去执行/404这个url。

2)exception + path,如LoginFailedException + /loginfailed,表示如果遇到登陆失败异常,就去执行后面这个url

3)没有status和exception,只有path,这相当于通配符,匹配所有异常情况。

接下来就该考虑如何注册了,照例给个接口就行了,如下图0506:

Spring是以bean打天下的,所以SpringBoot给的方法当然也是和bean相关。

只要向容器中注册一个该接口类型的bean即可,如下图07:

这些信息会被收集到并存好,如下图08:

然后在创建web服务器时添加进去就行了,以tomcat为例,如下图09:

可以看到最终转换为tomcat的错误映射,如下图10:

这里的setLocation、setErrorCode、setExceptionType三个setter方法,就对应于web.xml里的<location>、<error-code>、<exception-type>这三个标签。

至此,错误处理已经被注册好了。

SpringBoot仍需协助处理错误

有一点需要明白,SpringMVC交给tomcat的只是错误处理映射的匹配工作,但有些真正的错误处理还是要自己做的。

所以整个过程是这样的,SpringMVC随意抛出异常,这个异常会被抛到tomcat里面,tomcat获取异常类型并根据注册的错误处理映射关系找到一个url,然后调用这个url。

那么请问这个url指向哪里呢?很大概率又回到了SpringMVC里面了,是不是很有意思,哈哈。

tomcat就像一面镜子,SpringMVC向它发射了一束光线,经过反射后又回来了。只不过发射的是一个异常,回来的是一个url。

这个url对应的是能够处理这个错误的一个Controller的方法。这样执行这个Controller方法就等于处理了异常。

这个Controller是一个能够处理错误的Controller,所以就叫ErrorController。如下图11:

其实它主要是一个Marker接口,也就起一个标志作用。

下面是真正用于处理错误的Controller,实现了刚刚的标志接口,如下图12:

@RequestMapping方法就是处理错误的,既可以返回JSON,也可以返回视图页面。

我们可以自己写一个错误处理类,然后继承这个类,添加自己的错误处理方法,最后使用@Controller注解重新注册即可。

可以把一个异常映射成和它名称一样的url路径,如把Exception映射为/Exception,如下图13:

这两个方法,一个返回html页面,一个返回一个JSON。

备注:异常类型和它映射的url之间的关系,可以按自己的需求去规划,统一规则即可。

处理错误时,自然要获得错误相关信息才行,这个接口可以满足,如下图14:

可以获得错误属性和抛出的异常对象。

可以看到接口的两个方法都有WebRequest这个参数,说明错误信息是从request中获取出来的。

同时也说明有些错误信息是有人专门放入request中的,是SpringBoot放的,还是web服务器放的?

其实都有,比如异常对象是SpringBoot放的,响应状态码是web服务器(按Java web规范)放的。

这也说明web服务器执行错误处理的url时用的是转发(forward)而非重定向(redirect),因为要保留request中的信息。

还剩最后一个,错误视图解析器,如下图15:

SpringBoot自己提供了默认的视图解析器实现,默认去classpath下面的error目录下寻找.html视图页面。

如下图16:

支持状态码到页面的映射,如404默认映射为/error/404.html,500默认映射为/error/500.html。

如果没有这么具体的页面,还支持系列映射,如404映射为/error/4xx.html,500映射为5xx.html。

当然,默认的一般都无法满足需求,我们可以继承这个默认的类,然后重写视图解析方法。

最后把这个类注册为bean即可,这样SpringBoot就会使用我们的类了。如下图17:

本文总结,重要

1)用户使用SpringBoot提供的错误处理映射机制注册状态码和异常的映射url信息。

2)这些映射信息最终会被注册进web服务器中,如tomcat。

3)SpringBoot把异常抛给web服务器,web服务器根据异常找到对应的url,并执行它。

4)流程再次回到SpringBoot中,进入错误处理Controller的方法中,执行错误处理方法。

5)如果需要解析视图的,使用错误视图解析器进行视图解析。否则就是直接返回JSON。

其中用户能参与的就三步,注册异常映射,扩展错误处理Controller,扩展错误视图解析器。

具体参与方式文章中都有,无非就是实现接口或继承某个类,然后注册为bean即可。

>>> 玩转SpringBoot系列文章 <<<

【玩转SpringBoot】配置文件yml的正确打开姿势

【玩转SpringBoot】用好条件相关注解,开启自动配置之门

【玩转SpringBoot】给自动配置来个整体大揭秘

【玩转SpringBoot】看似复杂的Environment其实很简单

【玩转SpringBoot】翻身做主人,一统web服务器

>>> 品Spring系列文章 <<<

品Spring:帝国的基石

品Spring:bean定义上梁山

品Spring:实现bean定义时采用的“先进生产力”

品Spring:注解终于“成功上位”

品Spring:能工巧匠们对注解的“加持”

品Spring:SpringBoot和Spring到底有没有本质的不同?

品Spring:负责bean定义注册的两个“排头兵”

品Spring:SpringBoot轻松取胜bean定义注册的“第一阶段”

品Spring:SpringBoot发起bean定义注册的“二次攻坚战”

品Spring:注解之王@Configuration和它的一众“小弟们”

品Spring:bean工厂后处理器的调用规则

品Spring:详细解说bean后处理器

品Spring:对@PostConstruct和@PreDestroy注解的处理方法

品Spring:对@Resource注解的处理方法

品Spring:对@Autowired和@Value注解的处理方法

品Spring:真没想到,三十步才能完成一个bean实例的创建

品Spring:关于@Scheduled定时任务的思考与探索,结果尴尬了

>>> 热门文章集锦 <<<

毕业10年,我有话说

【面试】我是如何面试别人List相关知识的,深度有点长文

我是如何在毕业不久只用1年就升为开发组长的

爸爸又给Spring MVC生了个弟弟叫Spring WebFlux

【面试】我是如何在面试别人Spring事务时“套路”对方的

【面试】Spring事务面试考点吐血整理(建议珍藏)

【面试】我是如何在面试别人Redis相关知识时“软怼”他的

【面试】吃透了这些Redis知识点,面试官一定觉得你很NB(干货 | 建议珍藏)

【面试】如果你这样回答“什么是线程安全”,面试官都会对你刮目相看(建议珍藏)

【面试】迄今为止把同步/异步/阻塞/非阻塞/BIO/NIO/AIO讲的这么清楚的好文章(快快珍藏)

【面试】一篇文章帮你彻底搞清楚“I/O多路复用”和“异步I/O”的前世今生(深度好文,建议珍藏)

【面试】如果把线程当作一个人来对待,所有问题都瞬间明白了

Java多线程通关———基础知识挑战

品Spring:帝国的基石

作者是工作超过10年的码农,现在任架构师。喜欢研究技术,崇尚简单快乐。追求以通俗易懂的语言解说技术,希望所有的读者都能看懂并记住。下面是公众号的二维码,欢迎关注!

【玩转SpringBoot】让错误处理重新由web服务器接管的更多相关文章

  1. vs2015启动网站调试提示 HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容。 解决方法

    今天安装了vs2015 下载一个项目进行试用,启动调试的时候提示 HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容. 最可能的原因: 没有为请求的 URL ...

  2. vs2012启动网站调试提示 HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容

    启动vs2012调试网站的时候提示: HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容. 最可能的原因: 没有为请求的 URL 配置默认文档,并且没有在服 ...

  3. 错误提示:通过 Web 服务器的身份验证的用户无权打开文件系统上的文件

    //win7中iis配置好了可是网页打不开,为什么.? //错误提示:通过 Web 服务器的身份验证的用户无权打开文件系统上的文件 //解决办法1.右键单击你的网站根目录文件夹,如wwwroot文件夹 ...

  4. HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容

    今天把一个.NET的网站部署到IIS上打开网页的时候出现了这个错误,刚开始以为是没有配置默认页,但是直接打开固定的页面地址也不行. 于是怀疑是.NET版本的问题,但是看了一下程序的目标框架是4.0没错 ...

  5. ASP.NET遇到HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容

    当碰到这个问题的时候真的是让人很费解啊,就算是重新打开机器也不能够解决,但是下面的小技巧说不一定就可以解决这个问题了. 首先,打开IIS(Internet信息管理服务器),找到"功能&quo ...

  6. .net mvc HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容

    1. 检查服务器上是否安装了“HTTP重定向”功能和“静态内容压缩”功能(在添加/删除程序或增加角色处安装).这是我所遇到的问题: 2. 应用程序池要被配置为“集成” 3. 把.net 4.0安装在i ...

  7. HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容。

    解决方法: 找到目录浏览,打开,点击右边的启用就OK了.

  8. 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程

    生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...

  9. 【玩转SpringBoot】异步任务执行与其线程池配置

    同步代码写起来简单,但就是怕遇到耗时操作,会影响效率和吞吐量. 此时异步代码才是王者,但涉及多线程和线程池,以及异步结果的获取,写起来颇为麻烦. 不过在遇到SpringBoot异步任务时,这个问题就不 ...

随机推荐

  1. 异步任务AsyncTask使用解析

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更 ...

  2. pymongo的基本操作和使用--练习

    1.将MongoDB注册到电脑中 安装好MongoDB之后,如何使用MongoDB呢?来到安装目录D:/MongoDB/bin会有如下列表: 其中,mongod.exe是服务端,mongo.exe是客 ...

  3. android 活动监听是否点击某个view

    前述(写给做过web前端的人) 在web H5,如果如果判断当前是否点击某个元素,一般会这样写. window.addEventListener("touchstart",func ...

  4. 附011.Kubernetes-DNS及搭建

    一 Kubernetes DNS介绍 1.1 Kubernetes DNS发展 作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,因此需要一个集群范围内的DNS服务来完成从服务名到 ...

  5. JS进阶面试题整理(仅仅整理我做错的题)

    前几天看到掘金博客一篇文章,找到了这个JavaScript进阶问题列表:现在把地址贴出来,想找工作或者想要巩固自己JS的同学可以参考 该文档会不定时更新    一.箭头函数 箭头函数相当于匿名函数,并 ...

  6. Spring Cloud Alibaba(五)RocketMQ 异步通信实现

    本文探讨如何使用 RocketMQ Binder 完成 Spring Cloud 应用消息的订阅和发布. 介绍 RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的.高 ...

  7. Netty学习——Apache Thrift 简介和下载安装

    Netty学习——Apache Thrift 简介和下载安装 Apache Thrift 简介 本来由Facebook开发,捐献给了Apache,成了Apache的一个重要项目 可伸缩的,跨语言的服务 ...

  8. Spring Boot 最简单整合Shiro+JWT方式

    简介 目前RESTful大多都采用JWT来做授权校验,在Spring Boot 中可以采用Shiro和JWT来做简单的权限以及认证验证,在和Spring Boot集成的过程中碰到了不少坑.便结合自身以 ...

  9. “洞察千里”,华为云HiLens如何让无人车智行天下

    作者:华为云 Rosie 随着人工智能的普及和渗透,"无人"的场景越来越丰富,无人超市.无人车.无人机等已经融入我们的生活. 乘着这股热浪,华为云携手上海交通大学学生创新中心举办了 ...

  10. 【跟唐老师学习云网络】-第8篇 iptables - filter过滤功能

    [摘要] 前面的各种协议已经可以把基本可用的物理网络世界给形成了,在正常情况下,它可以玩的很溜.比如组个局域网办公,或者打个联机魔兽争霸,都没有什么问题. 一.背景介绍 前面的各种协议已经可以把基本可 ...