今天我们将研究Servlet异常和错误处理。不久前,我写了一篇关于Java异常处理的帖子,但是当涉及到Web应用程序时,我们需要更多的异常处理。
Servlet异常
如果您注意到,doGet()和doPost()方法会抛出javax.servlet.ServletException
和IOException
,让我们看看当我们从应用程序抛出这些异常时会发生什么。我将编写一个简单的Servlet来抛出Servlet异常。
package com.journaldev.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错误
I am sure you must have seen 404 error when you are trying to hit a URL that doesn’t exists. Let’s see how our servlet container responds to 404 error. If we send request for an invalid URL, we get response HTML like below image. Again it’s a generic HTML generated by server on our application behalf and hold little to no value to the user.
Servlet异常和错误处理
Servlet API支持配置在部署描述符中的自定义异常和错误处理servlet。这些servlet的整个目的是处理应用程序引发的异常或错误,并向用户发送有用的HTML响应。我们可以提供链接到应用程序主页或一些详细信息,让用户了解出了什么问题。因此,首先我们需要创建一个自定义的异常和错误处理servlet。我们可以为应用程序有多个异常和错误处理servlet,但为简单起见,我将创建一个单独的servlet,并将其用于处理异常和错误。AppExceptionHandler.java
package com.journaldev.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 {
// 分析servlet异常
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";
}
// 设置响应内容类型
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("Exception/Error Details ");
if(statusCode != 500){
out.write("Error Details
");
out.write("Status Code:"+statusCode+"
");
out.write("Requested URI:"+requestUri);
}else{
out.write("Exception Details
");
out.write("- Servlet Name:"+servletName+"
");
out.write("- Exception Name:"+throwable.getClass().getName()+"
");
out.write("- Requested URI:"+requestUri+"
");
out.write("- Exception Message:"+throwable.getMessage()+"
");
out.write("
");
}
out.write("
");
out.write("Home Page");
out.write("");
}
}
让我们看看如何在部署描述符中配置它,然后我们将了解它的实现和工作原理。
<?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>
正如你所看到的,使用error-page元素为应用程序指定异常处理器servlet非常容易。每个error-page元素应该有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应用程序设置异常处理器。如果你想在一个单一的异常处理器中处理运行时异常和所有其他异常,你可以将异常类型设置为Throwable。
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
如果存在多个错误页面条目,比如一个用于Throwable,一个用于IOException,而应用程序抛出FileNotFoundException,则将由IOException的错误处理程序处理。您还可以使用JSP页面作为异常处理程序,只需提供jsp文件的位置而不是servlet映射。这就是在Web应用程序中处理servlet异常的全部内容,希望您喜欢。
查看此系列中的其他文章: