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 文件上传和下载示例
bannerAds