Servlet错误处理大全:异常捕获、处理机制与实战案例
今天我们将研究Servlet异常和错误处理。之前我写过一篇关于Java异常处理的文章,但在处理Web应用程序时,我们需要更多的异常处理工作。
Servlet异常
如果你注意到的话,doGet()和doPost()方法会抛出javax.servlet.ServletException和IOException异常,让我们看看当我们从应用程序中抛出这些异常时会发生什么。我将编写一个简单的servlet来抛出ServletException。
package com.Olivia.servlet.exception;
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("/MyExceptionServlet")
public class MyExceptionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
throw new ServletException("GET method is not supported.");
}
}
现在当我们通过浏览器使用GET方法调用这个servlet时,我们会得到如下图所示的响应。由于浏览器只能理解HTML,当我们的应用程序抛出异常时,servlet容器会处理这个异常并生成一个HTML响应。这个逻辑是特定于servlet容器的。我正在使用Tomcat并收到这个错误页面。如果您使用其他服务器,如JBoss或Glassfish,您可能会得到不同的错误HTML响应。这个响应的问题是它对用户来说没有任何价值。它向用户展示了我们的应用程序类和服务器详细信息,对用户来说毫无意义,从安全的角度来看也不好。
Servlet错误
我确定你在尝试访问不存在的URL时一定见过404错误。让我们看看我们的Servlet容器对404错误做出的响应。如果我们发送对一个无效URL的请求,我们会得到类似下方图片所示的响应HTML。再次强调,这是服务器根据我们的应用生成的通用HTML,对用户来说几乎没有什么价值。
Servlet异常和错误处理
Servlet API提供了对自定义异常和错误处理servlet的支持,我们可以在部署描述符中进行配置。这些servlet的整个目的是处理应用程序引发的异常或错误,并向用户发送有用的HTML响应。我们可以提供应用程序主页的链接或一些详细信息,让用户知道出了什么问题。首先,我们需要创建一个自定义异常和错误处理servlet。我们可以为应用程序创建多个异常和错误处理servlet,但为了简单起见,我将创建一个单独的servlet并将其用于异常和错误。AppExceptionHandler.java
package com.Olivia.servlet.exception;
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("/AppExceptionHandler")
public class AppExceptionHandler extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processError(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processError(request, response);
}
private void processError(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// Analyze the servlet exception
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");
if (servletName == null) {
servletName = "Unknown";
}
String requestUri = (String) request
.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null) {
requestUri = "Unknown";
}
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("<html><head><title>Exception/Error Details</title></head><body>");
if(statusCode != 500){
out.write("<h3>Error Details</h3>");
out.write("<strong>Status Code</strong>:"+statusCode+"<br>");
out.write("<strong>Requested URI</strong>:"+requestUri);
}else{
out.write("<h3>Exception Details</h3>");
out.write("<ul><li>Servlet Name:"+servletName+"</li>");
out.write("<li>Exception Name:"+throwable.getClass().getName()+"</li>");
out.write("<li>Requested URI:"+requestUri+"</li>");
out.write("<li>Exception Message:"+throwable.getMessage()+"</li>");
out.write("</ul>");
}
out.write("<br><br>");
out.write("<a href=\"index.html\">Home Page</a>");
out.write("</body></html>");
}
}
让我们来看看我们如何在部署描述符中配置它,然后我们就会了解它的实施方式和工作原理。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletExceptionHandling</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/AppExceptionHandler</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
</web-app>
正如您所见,使用错误页面元素可以非常简单地为应用程序指定异常处理程序servlet。每个错误页面元素应该具有error-code或exception-type元素中的一个。我们在location元素中定义异常处理程序servlet。根据以上配置,如果应用程序抛出404错误或ServletException,将由AppExceptionHandler servlet处理。当出现这样的异常和错误情况时,servlet容器将调用异常处理程序servlet的相应HTTP方法,并传递请求和响应对象。请注意,我提供了doGet()和doPost()方法的实现,以便它可以处理GET和POST请求,并使用一个公共方法来处理它们。在servlet容器调用servlet处理异常之前,它在请求中设置一些属性,以获取有关异常的有用信息,其中一些属性是javax.servlet.error.exception、javax.servlet.error.status_code、javax.servlet.error.servlet_name和javax.servlet.error.request_uri。对于异常,状态码始终为500,对应于“内部服务器错误”,对于其他类型的错误,我们会得到不同的错误代码,如404、403等。使用状态码,我们的实现向用户呈现不同类型的HTML响应。它还提供一个指向应用程序主页的超链接。现在,当我们访问抛出ServletException的servlet时,我们会得到如下图像所示的响应。如果我们尝试访问一个无效的URL,将导致404响应,我们会得到如下图像所示的响应。这看起来不错,帮助用户轻松理解发生了什么,并为他们提供了前往正确位置的途径。它还避免向用户发送应用程序敏感信息。我们应该始终为我们的Web应用程序设置异常处理程序。如果要在单个异常处理程序中处理运行时异常和所有其他异常,可以将exception-type设置为Throwable。
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
如果有多个错误页面条目,假设一个是针对Throwable的,一个是针对IOException的,而应用程序抛出了FileNotFoundException,那么它将被IOException的错误处理程序处理。您也可以使用JSP页面作为异常处理程序,只需提供jsp文件的位置而不是servlet映射。这就是Web应用程序中的Servlet异常处理,希望您喜欢。
下载 Servlet 异常处理示例项目
请查阅本系列的其他文章。
- Java 网络应用程序
Java Servlet 教程
Java 中的会话管理
Servlet 过滤器
Servlet 监听器
Servlet 中的 Cookies
Servlet 文件上传和下载示例