`
chenlk823
  • 浏览: 35616 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

自定义 Tomcat 404错误页面

 
阅读更多
Tomcat 的错误页面是由 org.apache.catalina.valves.ErrorReportValve 类输出来的。如果想自定义错误页面,不需要修改该类。Servlet 规范声明了相关的API,只需要在每个 web 应用的 web.xml 里定义。可按照错误类型、错误代码配置。例如:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

<display-name>Welcome to Tomcat</display-name>
<description>
     Welcome to Tomcat
</description>

<error-page>
<error-code>404</error-code>
<location>/errorpages/404.jsp</location>
</error-page>  

<error-page>
  <exception-type>java.lang.Exception</exception-type>
  <location>/errorpages/exception.jsp</location>
 </error-page>

</web-app>

注意错误页面必须以“/”开头,这样任何path的404错误页面及exception错误都会映射到这两个文件。然后在本web引用的errorpages下面放置404.jsp, exception.jsp两个文件。

错误页面 404.jsp:

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.*" %>
<html>
<header>
<title>404 page</title>
<body>

<pre>
<%
    Enumeration<String> attributeNames = request.getAttributeNames();
    while (attributeNames.hasMoreElements())
    {
        String attributeName = attributeNames.nextElement();
        Object attribute = request.getAttribute(attributeName);
   out.println("request.attribute['" + attributeName + "'] = " + attribute);
    }
%>
</pre>

代码中输出了所有的 request 中的变量。从中也可以看到访问哪个文件出错,跳到哪个错误页面了,从而进行更详细、更人性化的错误处理。例如,提示可能的正确网址等等。

例如:访问一个不存在的页面 page_not_exist.html,显示的信息为:

request.attribute['javax.servlet.forward.request_uri'] = /page_not_exists.html
request.attribute['javax.servlet.forward.context_path'] =
request.attribute['javax.servlet.forward.servlet_path'] = /page_not_exists.html
request.attribute['javax.servlet.forward.path_info'] = /errorpages/404.jsp
request.attribute['javax.servlet.error.message'] = /page_not_exists.html
request.attribute['javax.servlet.error.status_code'] = 404
request.attribute['javax.servlet.error.servlet_name'] = default
request.attribute['javax.servlet.error.request_uri'] = /page_not_exists.html

注意,该错误页面必须大于512字节,否则IE将不予显示。因为IE默认只显示大于512字节的错误页面。Firefox中正常显示。可以添加一些其他信息,将页面大小扩充到512字节以上。如果仍不能显示,请检查IE设置,将该选项选中。




异常处理页面 exception.jsp:

<%@ page contentType="text/html; charset=UTF-8" isErrorPage="true" %>
<%@ page import="java.io.*" %>
<html>
<header>
<title>exception page</title>
<body>
<hr/>
<pre>
<%
response.getWriter().println("Exception: " + exception);

if(exception != null)
{
   response.getWriter().println("<pre>");
   exception.printStackTrace(response.getWriter());
   response.getWriter().println("</pre>");
}

response.getWriter().println("<hr/>");
%>

注意isErrorPage熟悉必须为true,才能使用exception对象。exception即捕捉到的异常。此处可以对exception进行处理,比如记录日志、重定向等等。这里把exception trace打印出来了。

500、505 等错误页面的处理类似于404。

----------------------------------------------------------------------------------

还有一种方法是,自定义ErrorReportValve。适合context比较多的情况。自己实现一个ErrorReportValve,就可以适用于所有的404、505、500等错误了。实现后需打成 jar 包,放置到 tomcat 的全局lib里,并配置到tomcat 的server.xml里:

      <Host name="localhost" appBase="webapps"

            unpackWARs="true" autoDeploy="true" errorReportValveClass="com.helloweenpad.xxxxx.OurCustomizedErrorReportValve"

            xmlValidation="false" xmlNamespaceAware="false">

相关 tomcat 的文档为:

errorReportValveClass
Java class name of the error reporting valve which will be used by this Host. The responsability of this valve is to output error reports. Setting this property allows to customize the look of the error pages which will be generated by Tomcat. This class must implement the org.apache.catalina.Valve interface. If none is specified, the value org.apache.catalina.valves.ErrorReportValve will be used by default.



实现方式见 Tomcat 的 org.apache.catalina.valves.ErrorReportValve 类:




/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package org.apache.catalina.valves;


import java.io.IOException;
import java.io.Writer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Globals;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.util.StringManager;

/**
* <p>Implementation of a Valve that outputs HTML error pages.</p>
*
* <p>This Valve should be attached at the Host level, although it will work
* if attached to a Context.</p>
*
* <p>HTML code from the Cocoon 2 project.</p>
*
* @author Remy Maucherat
* @author Craig R. McClanahan
* @author <a href="mailto:nicolaken@supereva.it">Nicola Ken Barozzi</a> Aisa
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author Yoav Shapira
* @version $Revision: 543307 $ $Date: 2007-06-01 01:08:24 +0200 (Fri, 01 Jun 2007) $
*/

public class ErrorReportValve
    extends ValveBase {


    // ----------------------------------------------------- Instance Variables


    /**
     * The descriptive information related to this implementation.
     */
    private static final String info =
        "org.apache.catalina.valves.ErrorReportValve/1.0";


    /**
     * The StringManager for this package.
     */
    protected static StringManager sm =
        StringManager.getManager(Constants.Package);


    // ------------------------------------------------------------- Properties


    /**
     * Return descriptive information about this Valve implementation.
     */
    public String getInfo() {

        return (info);

    }


    // --------------------------------------------------------- Public Methods


    /**
     * Invoke the next Valve in the sequence. When the invoke returns, check
     * the response state, and output an error report is necessary.
     *
     * @param request The servlet request to be processed
     * @param response The servlet response to be created
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void invoke(Request request, Response response)
        throws IOException, ServletException {

        // Perform the request
        getNext().invoke(request, response);

        Throwable throwable =
            (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);

        if (response.isCommitted()) {
            return;
        }

        if (throwable != null) {

            // The response is an error
            response.setError();

            // Reset the response (if possible)
            try {
                response.reset();
            } catch (IllegalStateException e) {
                ;
            }

            response.sendError
                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

        }

        response.setSuspended(false);

        try {
            report(request, response, throwable);
        } catch (Throwable tt) {
            ;
        }

    }


    // ------------------------------------------------------ Protected Methods


    /**
     * Prints out an error report.
     *
     * @param request The request being processed
     * @param response The response being generated
     * @param throwable The exception that occurred (which possibly wraps
     * a root cause exception
     */
    protected void report(Request request, Response response,
                          Throwable throwable) {

        // Do nothing on non-HTTP responses
        int statusCode = response.getStatus();

        // Do nothing on a 1xx, 2xx and 3xx status
        // Do nothing if anything has been written already
        if ((statusCode < 400) || (response.getContentCount() > 0))
            return;

        String message = RequestUtil.filter(response.getMessage());
        if (message == null)
            message = "";

        // Do nothing if there is no report for the specified status code
        String report = null;
        try {
            report = sm.getString("http." + statusCode, message);
        } catch (Throwable t) {
            ;
        }
        if (report == null)
            return;

        StringBuffer sb = new StringBuffer();

        sb.append("<html><head><title>");
        sb.append(ServerInfo.getServerInfo()).append(" - ");
        sb.append(sm.getString("errorReportValve.errorReport"));
        sb.append("</title>");
        sb.append("<style><!--");
        sb.append(org.apache.catalina.util.TomcatCSS.TOMCAT_CSS);
        sb.append("--></style> ");
        sb.append("</head><body>");
        sb.append("<h1>");
        sb.append(sm.getString("errorReportValve.statusHeader",
                               "" + statusCode, message)).append("</h1>");
        sb.append("<HR size=\"1\" noshade=\"noshade\">");
        sb.append("<p><b>type</b> ");
        if (throwable != null) {
            sb.append(sm.getString("errorReportValve.exceptionReport"));
        } else {
            sb.append(sm.getString("errorReportValve.statusReport"));
        }
        sb.append("</p>");
        sb.append("<p><b>");
        sb.append(sm.getString("errorReportValve.message"));
        sb.append("</b> <u>");
        sb.append(message).append("</u></p>");
        sb.append("<p><b>");
        sb.append(sm.getString("errorReportValve.description"));
        sb.append("</b> <u>");
        sb.append(report);
        sb.append("</u></p>");

        if (throwable != null) {

            String stackTrace = getPartialServletStackTrace(throwable);
            sb.append("<p><b>");
            sb.append(sm.getString("errorReportValve.exception"));
            sb.append("</b> <pre>");
            sb.append(RequestUtil.filter(stackTrace));
            sb.append("</pre></p>");

            int loops = 0;
            Throwable rootCause = throwable.getCause();
            while (rootCause != null && (loops < 10)) {
                stackTrace = getPartialServletStackTrace(rootCause);
                sb.append("<p><b>");
                sb.append(sm.getString("errorReportValve.rootCause"));
                sb.append("</b> <pre>");
                sb.append(RequestUtil.filter(stackTrace));
                sb.append("</pre></p>");
                // In case root cause is somehow heavily nested
                rootCause = rootCause.getCause();
                loops++;
            }

            sb.append("<p><b>");
            sb.append(sm.getString("errorReportValve.note"));
            sb.append("</b> <u>");
            sb.append(sm.getString("errorReportValve.rootCauseInLogs",
                                   ServerInfo.getServerInfo()));
            sb.append("</u></p>");

        }

        sb.append("<HR size=\"1\" noshade=\"noshade\">");
        sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
        sb.append("</body></html>");

        try {
            try {
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
            } catch (Throwable t) {
                if (container.getLogger().isDebugEnabled())
                    container.getLogger().debug("status.setContentType", t);
            }
            Writer writer = response.getReporter();
            if (writer != null) {
                // If writer is null, it's an indication that the response has
                // been hard committed already, which should never happen
                writer.write(sb.toString());
            }
        } catch (IOException e) {
            ;
        } catch (IllegalStateException e) {
            ;
        }
       
    }


    /**
     * Print out a partial servlet stack trace (truncating at the last
     * occurrence of javax.servlet.).
     */
    protected String getPartialServletStackTrace(Throwable t) {
        StringBuffer trace = new StringBuffer();
        trace.append(t.toString()).append('\n');
        StackTraceElement[] elements = t.getStackTrace();
        int pos = elements.length;
        for (int i = 0; i < elements.length; i++) {
            if ((elements[i].getClassName().startsWith
                 ("org.apache.catalina.core.ApplicationFilterChain"))
                && (elements[i].getMethodName().equals("internalDoFilter"))) {
                pos = i;
            }
        }
        for (int i = 0; i < pos; i++) {
            if (!(elements[i].getClassName().startsWith
                  ("org.apache.catalina.core."))) {
                trace.append('\t').append(elements[i].toString()).append('\n');
            }
        }
        return trace.toString();
    }

}



分享到:
评论

相关推荐

    在Tomcat中配置404自定义错误页面详解

    主要介绍了在Tomcat中配置404自定义错误页面全解,需要的朋友可以参考下

    tomcat6、7、8、9, maven3.5

    除了修复关键安全相关的错误,Apache Tomcat 3.2.x分支上的开发已停止。 的Apache Tomcat 3.1.X。3.1版本包含对Apache Tomcat 3.0的几个改进,包括servlet重新加载,WAR文件支持和为IIS和Netscape Web服务器添加的...

    nginx生产环境配置+错误页面+jar启动终止脚本

    包含了springboot 打包jar部署的一键启动和终止脚本(.sh)、nginx生产环境配置文件(.conf)参考示例和自定义错误页面资源,适合中小公司(个人)Linux系统部署springboot项目

    jsp自定义标签实例

    这是本人自己写的,里面包括传参与不传参的标签,很方便,步骤很详细。所有就上传上来了。

    springboot、dubbo学习资料(推荐)

    Spring Boot默认使用嵌入式Tomcat,默认没有页面来处理404等常见错误。因此,为了给用户最佳的使用体验,404等常见错误需要我们自定义页面来处理。

    security-test:Spring安全测试

    -403和404错误页面 -通过JDBC验证用户和密码 -BCrypt保护密码 -Https支持 -运行时重载权限 -启用Csrf Https支持 要启用https,请执行以下步骤: 本示例假设您使用的是Tomcat服务器。 打开一个终端,转到TOMCAT_...

    cas-overlay-template-6.4 服务端代码

    4.CAS-自定义错误信息 5.CAS-识别json文件 6.CAS-页面缓存记住我 7.CAS-cookie设置 8.CAS-tgc设置 9.CAS-登出 10.CAS-redisCluster集群存储ticket(相应redis必须配置成cluster集群) 11.CAS-加密存储ticket 12.CAS-...

    光明在线页面编辑器「Luminate Online Page Editor」-crx插件

    *添加了对编辑为PageBuilder页面,StoryBuilder文章和事件创建的自定义TellAFriend页面的支持。版本:1.9(05-JUL-2013)*修复了从JServ迁移到Tomcat后,Luminate Online URL语法更改引起的错误。版本:1.8(2013年3...

    大学生互动平台1(ssh+ext+jfreechart+部分报表功能)

    页面显示采用jsp部分用struts标签,业务逻辑层采用spring,持久层采用hibernate,数据库采用mysql.(用户名密码都是root),tomcat端口号8080.后台界面采用ajax框架ext非常漂亮。可以管理多个社团网站。采用jfreechart...

    JavaMelody能够监测Java或Java EE应用程序服务器.rar

    并以图表的方式显示:Java内存和Java CPU使用情况,用户Session数量,JDBC连接数,和http请求、sql请求、jsp页面与业务接口方法(EJB3、Spring、 Guice)的执行数量,平均执行时间,错误百分比等。图表可以按天,周...

    基于JavaWEB+SSM+mysql框架构建的在线商城系统源码+数据库+项目说明(课程设计).zip

    若在Tomcat中部署,Maven文件中已经配置好直接在线部署,使用 maven tomcat7:deploy 可直接在线部署 (需先配置好Tomcat) 3. 导入数据库small.sql,在 \src\main\resources\jdbc.properties 中配置数据库 4. ...

    JSP开发实用技术整理

    1.错误页404或500等显示页面配置 1 2.过滤器配置 1 3.编码过滤的类写法 2 4.一般过滤类的写法 3 5.Hibernate事务写法(1) 4 6.Hibernate查询(1) 4 7.网页中&lt;%if%&gt; 5 8.java简单的获取系统网卡mac地址 5 9. 增加tomcat...

    springboot参考指南

    1. 介紹 2. I. Spring Boot文档 i. 1....ii. 2....iii....iv....v....vi....vii....3. II....i....ii....i....iii....i....i....ii....ii....i....ii....iii....iv....v....vi....iii....iv....v....vi....vii....i.... 自定义'白标'(whitelabel,可以了解下相关理念)错误页面 x. 71...

    appjsf:系统基础jsf

    使用 hibernate ehcache 的缓存策略- 使用Hibernate环境的版本-context.xml 中的连接池- 使用 jasperlerpot 的 pdf 报告-验证- 授权阶段监听器-md5 密码加密-上传文件- 发送电子邮件- 过期页面警告-自定义错误页面-...

    SpringBootAngularHTML5:Spring Boot 2 + Angular 11 + HTML5路由器模式+ HTTP拦截器+延迟加载的模块

    此html5 router模式提供漂亮的URL,但具有默认值:如果为应用程序提供服务的HTTP服务器未提供RewriteRule,则刷新页面(或直接访问页面)将给您404 HTTP错误。 动态处理base-href也可能很棘手。 在这里,它由...

    java8源码-SpaceX-Web:version1.0构建高可用(物理库,内存库)web应用;version2.0web服务性能提升:to

    version2.0为web服务性能提升:tomcat集群与页面分离版本; version3.0为分布式架构web系统:实现了分布式锁,队列等。版本与1.0,2.0区别较大,另起一个名为“SpaceX-Web-Distributed”项目。 maven依赖 version1.0 ...

    22春“计算机科学与技术”专业《web技术》在线作业一答案参考6.docx

    Tomcat建立的web应用对文件的大小写是不敏感的。( ) A.正确 B.错误 参考答案:B 3. 若要以加粗宋体、6号字显示"hello"以下用法中,正确的是( ) 若要以加粗宋体、6号字显示"hello"以下用法中,正确的是( ) A、bfont ...

    贝岭的matlab的代码-uball:球

    自定义错误页面 多对多数据库关系 使用 Materialise 设计样式 启用 HTTPS 进行中的功能 ... 内置 - Java - 依赖管理 - Spring Boot 框架 - Spring安全 - MySQL - Apache Tomcat - 百里香 - Hibernate - jQuery - ...

Global site tag (gtag.js) - Google Analytics