使用Tomcat,一定见到过404,500的时候,见到过Tomcat提供的错误页面,例如请求的资源找不到的时候,响应状态码为404,这个时候的错误页面是这样的:

这些错误页面是 如何生成及定位展示的 ,如果我们要 自定义一些错误页面 ,又要怎么做呢?今天我们一起来看看,Tomcat中提供的ErrorPage处理。

我们以Manager应用为例,来了解整个流程。

  1. 首先,Manager应用的web.xml中,包含如下关于ErrorPage的配置:

这些配置,在应用部署,解析web.xml文件的时候,都会生成ErrorPage对应,设置到对应Context应用的属性中。

for (ErrorPage errorPage : webxml.getErrorPages().values() ) {

context. addErrorPage (errorPage);

}

(web.xml文件解析及应用部署,可以参考前面的文章《 WEB应用是怎样部署的?》)

下面的代码,就是StandardContext添加ErrorPage的内容。我们看到,按照对应配置的状态码,每个对应一个errorPage对象,保存到Map中。

上面是context设置errorPage。在应用请求处理时,如果对应的资源不存在,或者产生异常时,此时就需要根据配置的errorPage,进行对应的展示。

例如下面的代码,是在对应用的资源树上查找,如果不存在就会直接以 SC_NOT_FOUND 响应。

sendError的作用,是进行一个error标识的设置,便于后面对于该状态的使用。在其内部主要进行errorState和状态码的设置。

public boolean setError() {

boolean result = errorState .compareAndSet(0, 1 );

if (result) {

Wrapper wrapper = getRequest().getWrapper();

if (wrapper != null) {

wrapper.incrementErrorCount();

}

}

return result;

}

我们前面介绍过,整个请求处理流程中,会在Pipeline中包含一系列的Valve。在资源找不到或者异常产生时,Valve的后处理逻辑中, 在StandardHostValve中,后处理的代码有如下的逻辑

// Look for (and render if found) an application level error page

if (response. isErrorReportRequired ()) {

if (t != null) {

throwable(request, response, t);

} else {

status (request, response);

}

}

这里的response.isErrorReportRequired获取的就是上面对于error标识的设置。在这里,如果有异常产生会打印异常,如果是其它的状态标识,会走status处理。

status方法中,最主要的逻辑,就是根据状态码,获取对应配置的错误页面。

int statusCode = response.getStatus();

ErrorPage errorPage = context.findErrorPage(statusCode);

if (errorPage == null) {

// Look for a default error page

errorPage = context.findErrorPage(0);

}

status的代码,在获取对应的errorPage之后,会进行一个custom的操作,定向到对应的错误页面。代码如下:

从上面的代码中,我们看到定向的方式,使用的是RequestDispatcher. forward

ServletContext servletContext =

request.getContext().getServletContext();

RequestDispatcher rd =

servletContext.getRequestDispatcher( errorPage.getLocation() );

rd.forward(request.getRequest(), response.getResponse());

上面就是整个自定义errorPage的处理流程,概括起来,就是根据指定的错误页面位置,再在对应的状态码match的时候,进行forward 的处理。(重定向和转发,可以参见前面的文章《关于重定向和转发》)所以此处,我们可以进行一个个性化的404或者500的页面处理。

当然,ErrorPage的配置中,可以声明一个exceptionType,在指定的异常产生时,对应到相应的page上面,原理类似。

除上之外,需要说明的一点是,有些应用中,我们并没有显示的指定errorPage,但是在应用的请求中,依然可以看到熟悉的Tomcat错误页面。这个是因为,在Pipeline中,还有一个Vavle, ErrorReportValve

依然走前面的错误处理流程时,在根据错误码获取errorPage的时候,因为没有对应的配置,custom处理就跳过了。整个错误展示留给后面的ErrorReportValve。

在它的report方法中,对于状态码小于400的不做处理,其他的就会生成我们熟悉的错误页面,同时,加上对应的状态码,提示信息,如果有相应的stackTrace,会遍历显示到 页面上。

所以,这个其实是Tomcat代码里硬编码的一个。内容基本是这个样子:

所以,对于未指定errorPage的应用,看到的是相同样式的错误页面的,就是因为上面的原因。

Tomcat 的 ErrorPage 实现原理分析的更多相关文章

  1. tomcat原理分析与简单实现

    tomcat原理分析与简单实现 https://blog.csdn.net/u014795347/article/details/52328221 2016年08月26日 14:48:18 卫卫羊习习 ...

  2. Tomcat源码分析——请求原理分析(下)

    前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在& ...

  3. Tomcat源码分析——请求原理分析(中)

    前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...

  4. Tomcat源码分析——请求原理分析(上)

    前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程 ...

  5. tomcat无法正常关闭问题分析及解决

    问题描述 通常,我们都会直接使用tomcat提供的脚本执行关闭操作,如下: # sh bin/shutdown.sh Using CATALINA_BASE: /usr/local/apache-to ...

  6. SpringBoot入门(0) HelloWorld的实现与原理分析

    SpringBoot(0) HelloWorld的实现与原理分析 一.环境准备 1.1 环境约束 –jdk1.8:Spring Boot 推荐jdk1.7及以上:java version “1.8.0 ...

  7. Spring Boot 实战与原理分析视频课程

    Spring Boot 实战与原理分析视频课程 链接:https://pan.baidu.com/share/init?surl=PeykcoeqZtd1d9lN9V_F-A 提取码: 关注公众号[G ...

  8. Tomcat之JSP运行原理之小试牛刀

    最近空闲看了下JSP/Servlet,以前只知道用JSP,但是对其运行原理知之甚少,今在此做些笔记,以备查阅. 首先简要描述下其运行过程,然后结合Tomcat源码作简要分析. JSP运行过程: 第一步 ...

  9. Servlet过滤器介绍之原理分析

    zhangjunhd 的BLOG     写留言去学院学习发消息 加友情链接进家园 加好友 博客统计信息 51CTO博客之星 用户名:zhangjunhd 文章数:110 评论数:858 访问量:19 ...

随机推荐

  1. 揭秘Facebook首个数据中心:全球15亿用户的账户信息都在这里

      投递人 itwriter 发布于 2016-07-14 17:41 评论(0) 原文链接 [收藏]  对于 Facebook.Google 这种体量的科技公司而言,数据中心应该是处于军事级别的保密 ...

  2. matlab 中randn randi rand randsrc的用法以及区别

    1,rand 生成均匀分布的伪随机数.分布在(0~1)之间 主要语法:rand(m,n)生成m行n列的均匀分布的伪随机数                      rand(m,n,'double') ...

  3. 70 sudo-用来以其他身份来执行命令

    sudo命令用来以其他身份来执行命令,预设的身份为root.在/etc/sudoers中设置了可执行sudo指令的用户.若其未经授权的用户企图使用sudo,则会发出警告的邮件给管理员.用户使用sudo ...

  4. 1021mysql 全外连接

    mysql 不支持全外连接,那么使用union all进行替换 -- 其他数据库 SELECT * FROM aa aFULL OUTER JOIN bb b ON a.col1=b.col1AND ...

  5. openvpn的部署

    http://www.gaohuirong.cn/openvpn/2016/04/12/linux-install-openvpn.html

  6. [转]为什么我要用 Node.js? 案例逐一介绍

    原文地址:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  7. gbdt推导和代码

    GBDT算法推导过程 m次迭代,n个类别,那么就意味着学习了m*n棵回归树 train过程:假设有8个训练样本,3个类别 步骤一.假设所有样本的F矩阵,F矩阵是8*3的,F矩阵刚开始全为0,而实际每个 ...

  8. hdu1161 欧拉路

    欧拉路径是指能从一个点出发能够“一笔画”完整张图的路径:(每条边只经过一次而不是点) 在无向图中:如果每个点的度都为偶数 那么这个图是欧拉回路:如果最多有2个奇数点,那么出发点和到达点必定为该2点,那 ...

  9. bzoj3224

    学习了下treap #include<iostream> #include<cstdio> #include<cstdlib> using namespace st ...

  10. eclipse-mvn打包跳过junit测试类

    修改pom.xml,在build选项加上plugins的这段如下: <build> ..... <plugins> <plugin> <groupId> ...