0%

异常处理

Java Web 异常处理:Servlet 错误页面与异常拦截机制

在 Java Web 应用中,异常处理是保障应用稳定性和用户体验的关键环节。Servlet 容器提供了灵活的异常处理机制,允许开发者通过配置错误页面或自定义异常处理器,统一捕获和处理请求过程中出现的异常(如 404 资源不存在、500 服务器错误、自定义业务异常等)。本文将详细解析 Servlet 异常处理的配置方式、核心对象及实践技巧。

Servlet 异常处理的核心机制

Servlet 容器通过错误页面配置异常属性传递实现异常处理:

  1. 当应用抛出未捕获的异常或返回特定错误码(如 404、500)时,容器会拦截请求;
  2. 根据预配置的规则(错误码或异常类型),将请求转发到指定的错误处理器(如 Servlet、JSP);
  3. 容器在请求域中设置异常相关属性,供错误处理器获取详细信息(如错误码、异常堆栈)。

异常处理的配置方式

XML 配置(web.xml

通过 web.xml<error-page> 标签配置错误页面,支持按错误码异常类型匹配:

(1)按错误码配置

针对 HTTP 状态码(如 404、500)指定处理页面:

1
2
3
4
5
6
7
8
9
10
11
<!-- 处理 404 资源不存在错误 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location> <!-- 错误处理器路径 -->
</error-page>

<!-- 处理 500 服务器内部错误 -->
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
(2)按异常类型配置

针对特定异常类型(如 ArithmeticException、自定义 BusinessException)指定处理页面:

1
2
3
4
5
6
7
8
9
10
11
<!-- 处理算术异常(如除以零) -->
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/ExceptionHandler</location> <!-- 自定义 Servlet 处理器 -->
</error-page>

<!-- 处理自定义业务异常 -->
<error-page>
<exception-type>com.example.BusinessException</exception-type>
<location>/error/business.jsp</location>
</error-page>

注解配置(Servlet 3.0+)

Servlet 3.0 及以上支持通过注解 @WebServleterrorPage 属性配置错误页面,或直接在异常处理器上使用 @WebServlet 并结合 web.xml<error-page>

示例:自定义异常处理 Servlet

1
2
3
4
5
6
7
8
9
10
11
12
@WebServlet("/ExceptionHandler")
public class ExceptionHandler extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 处理异常逻辑(见下文“获取异常信息”)
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

获取异常信息:请求域中的异常属性

当容器将请求转发到错误处理器时,会在 HttpServletRequest 的请求域中设置以下属性,用于获取异常详情:

属性键 类型 描述
javax.servlet.error.status_code Integer HTTP 状态码(如 404、500)
javax.servlet.error.exception_type Class<?> 异常类型的 Class 对象(如 ArithmeticException.class
javax.servlet.error.message String 错误消息(如异常的 getMessage() 内容)
javax.servlet.error.request_uri String 触发异常的请求 URI(如 /user/123
javax.servlet.error.exception Throwable 异常对象(可调用 printStackTrace() 打印堆栈)
javax.servlet.error.servlet_name String 触发异常的 Servlet 名称(如 UserServlet

示例:在异常处理器中获取信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@WebServlet("/ExceptionHandler")
public class ExceptionHandler extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();

// 从请求域获取异常信息
Integer statusCode = (Integer) req.getAttribute("javax.servlet.error.status_code");
String message = (String) req.getAttribute("javax.servlet.error.message");
String requestUri = (String) req.getAttribute("javax.servlet.error.request_uri");
Throwable exception = (Throwable) req.getAttribute("javax.servlet.error.exception");

// 输出错误信息
out.println("<h1>错误处理页面</h1>");
out.println("状态码:" + statusCode + "<br>");
out.println("错误消息:" + message + "<br>");
out.println("请求 URI:" + requestUri + "<br>");

// 打印异常堆栈
if (exception != null) {
out.println("<h3>异常堆栈:</h3>");
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
out.println("<pre>" + sw.toString() + "</pre>");
}
}
}

异常处理的执行流程

  1. 异常触发
    • 应用抛出未捕获的异常(如 throw new ArithmeticException());
    • 容器返回特定 HTTP 状态码(如请求不存在资源时返回 404)。
  2. 容器拦截
    容器根据 web.xml<error-page> 配置,匹配错误码或异常类型。
  3. 转发请求
    容器将请求转发到 <location> 指定的错误处理器(Servlet 或 JSP),并在请求域中设置异常属性。
  4. 处理响应
    错误处理器读取请求域中的异常信息,生成友好的错误页面返回给客户端。

最佳实践

  1. 统一错误页面
    为常见错误码(404、500)和通用异常(Exception)配置统一处理页面,避免用户看到原始异常堆栈。

  2. 区分环境

    • 开发环境:显示详细异常信息(便于调试);
    • 生产环境:显示友好提示(如 “系统繁忙,请稍后再试”),同时记录详细日志。
  3. 日志记录
    在异常处理器中通过日志框架(如 Logback、Log4j)记录异常堆栈,便于问题排查:

    1
    2
    3
    // 记录异常日志
    Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);
    logger.error("请求 {} 发生错误", requestUri, exception);
  1. 自定义异常类型
    定义业务异常(如 BusinessException),并为其配置专属处理器,实现业务与系统异常的分离处理。

  2. 避免循环错误
    确保错误处理器本身不会抛出异常,否则容器可能返回默认错误页面(如 Tomcat 的 404 页面)

欢迎关注我的其它发布渠道