Servlet 异常错误处理

Servlet 异常错误处理

当一个 Servlet 抛出异常时,Servlet 容器会去 web.xml 中检查是否配置了对应的 <error-page> 来显示异常信息。可以为不同的异常类型或 HTTP 错误码配置不同的错误页面。

通过错误响应码设置错误页面

首先配置一个用于显示异常信息的 Servlet 及其映射:

<!-- 显示异常信息的Servlet -->
<servlet>
    <servlet-name>errorservlet</servlet-name>
    <servlet-class>MyErrorServlet</servlet-class>
</servlet>
<!-- servlet 映射 -->
<servlet-mapping>
    <servlet-name>errorservlet</servlet-name>
    <url-pattern>/error</url-pattern>
</servlet-mapping>Code language: HTML, XML (xml)

通过错误码配置错误页面,当发生 404 错误时跳转到 /error

<error-page>
    <error-code>404</error-code>
    <location>/error</location>
</error-page>Code language: HTML, XML (xml)

对应的 MyErrorServlet 类:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyErrorServlet")
public class MyErrorServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().append("出错了");
    }

    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
            throws ServletException, IOException {
        super.service(arg0, arg1);
    }

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        super.service(arg0, arg1);
    }
}Code language: JavaScript (javascript)

注意:如果运行时出现以下错误:

java.lang.ClassCastException: org.eclipse.wst.server.preview.internal.WTPErrorHandler cannot be cast to org.eclipse.jetty.servlet.ErrorPageErrorHandlerCode language: CSS (css)

说明你配置的服务器不是 Tomcat,建议将 Eclipse 的服务器运行时环境配置为 Tomcat 服务器。

访问一个不存在的 URL 地址时,将触发 404 错误并跳转到 /error 对应的 Servlet。

通过异常类型设置错误页面

除了按错误码配置,还可以为特定的异常类型指定处理 Servlet:

<error-page>
    <exception-type>java.io.IOException</exception-type>
    <location>/error2</location>
</error-page>Code language: HTML, XML (xml)

当出现 IOException 时,交由 /error2 地址对应的 Servlet 处理。

异常信息展示 Servlet 示例

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyErrorServlet")
public class MyErrorServlet2 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception"); // 获取异常对象
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); // 获取错误状态码
        String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name"); // Servlet 的名称
        if (servletName == null) {
            servletName = "Unknown";
        }
        String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");
        if (requestUri == null) {
            requestUri = "Unknown";
        }
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        String title = "foxdevelop.com Error/Exception 信息";

        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body>\n");
        out.println("<h1>显示错误信息</h1>");
        if (throwable == null && statusCode == null) {
            out.println("<h2>错误信息丢失</h2>");
            out.println("请返回 <a href=\"" +
                response.encodeURL("http://localhost:8080/") +
                "\">主页</a>。");
        } else if (statusCode != null) {
            out.println("错误代码 : " + statusCode);
        } else {
            out.println("<h2>错误信息</h2>");
            out.println("Servlet Name : " + servletName +
                "</br></br>");
            out.println("异常类型 : " +
                throwable.getClass().getName() +
                "</br></br>");
            out.println("请求 URI: " + requestUri +
                "<br><br>");
            out.println("异常信息: " +
                throwable.getMessage());
        }
        out.println("</body>");
        out.println("</html>");
    }

    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
            throws ServletException, IOException {
        super.service(arg0, arg1);
    }

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
            throws ServletException, IOException {
        super.service(arg0, arg1);
    }
}Code language: JavaScript (javascript)

配置该 Servlet

<servlet>
    <servlet-name>MyErrorServlet2</servlet-name>
    <servlet-class>MyErrorServlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>MyErrorServlet2</servlet-name>
    <url-pattern>/err2</url-pattern>
</servlet-mapping>
<error-page>
    <exception-type>java.io.IOException</exception-type>
    <location>/err2</location>
</error-page>Code language: HTML, XML (xml)

在另一个 Servlet 的 doGet 中抛出异常:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    throw new IOException("");
}Code language: JavaScript (javascript)

访问该 Servlet 时,会触发 IOException,容器将跳转到 /err2 对应的 Servlet 显示异常详情。

全局异常捕获

如果希望所有未捕获的异常都通过同一个 Servlet 处理,可以配置 java.lang.Throwable 类型:

<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/err3</location>
</error-page>Code language: HTML, XML (xml)

这样无论抛出何种异常,都会交由 /err3 对应的 Servlet 统一处理。

错误页面中可用的请求属性

属性名类型说明
javax.servlet.error.exceptionThrowable异常对象
javax.servlet.error.status_codeIntegerHTTP 状态码
javax.servlet.error.servlet_nameString发生异常的 Servlet 名称
javax.servlet.error.request_uriString引发异常的请求 URI

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注