今天我们将探讨Servlet例外和错误处理. 有一段时间,我写了一篇关于 **(Java中的例外处理)( / 社区 / 教程 / 例外处理在Java)**的文章,但当涉及到Web应用程序时,我们需要在Java中比正常的例外处理更多。
服务例外
如果你注意到,doGet() 和 doPost() 方法投放javax.servlet.ServletException
和IOException
,让我们看看当我们从我们的应用程序中投放这些例外时会发生什么。
1package com.journaldev.servlet.exception;
2
3import java.io.IOException;
4import javax.servlet.ServletException;
5import javax.servlet.annotation.WebServlet;
6import javax.servlet.http.HttpServlet;
7import javax.servlet.http.HttpServletRequest;
8import javax.servlet.http.HttpServletResponse;
9
10@WebServlet("/MyExceptionServlet")
11public class MyExceptionServlet extends HttpServlet {
12 private static final long serialVersionUID = 1L;
13
14 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
15 throw new ServletException("GET method is not supported.");
16 }
17
18}
Now when we invoke this servlet through browser with GET method, we get response like below image. Since browser understand only HTML, when our application throw exception, servlet container processes the exception and generate a HTML response. This logic is specific to servlet container. I am using tomcat and getting this error page. If you will use some other servers like JBoss or Glassfish, you might get different error HTML response. The problem with this response is that it's of no value to user. Also it's showing our application classes and server details to user that makes no sense to user and it's not good from security point of view.
服务错误
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 支持我们可以在部署描述器中配置的自定义例外和错误处理器服务器服务器。这些服务器的全部用途是处理应用程序提出的例外或错误,并向用户发送有用的 HTML 响应。我们可以提供链接到应用程序主页或一些细节,让用户知道错误发生了什么。所以首先我们需要创建自定义例外和错误处理器服务器。我们可以为应用程序提供多个例外和错误处理器服务器,但为了简单,我会创建一个单一的服务器,并将其用于例外和错误。
1package com.journaldev.servlet.exception;
2
3import java.io.IOException;
4import java.io.PrintWriter;
5
6import javax.servlet.ServletException;
7import javax.servlet.annotation.WebServlet;
8import javax.servlet.http.HttpServlet;
9import javax.servlet.http.HttpServletRequest;
10import javax.servlet.http.HttpServletResponse;
11
12@WebServlet("/AppExceptionHandler")
13public class AppExceptionHandler extends HttpServlet {
14 private static final long serialVersionUID = 1L;
15
16 protected void doGet(HttpServletRequest request,
17 HttpServletResponse response) throws ServletException, IOException {
18 processError(request, response);
19 }
20
21 protected void doPost(HttpServletRequest request,
22 HttpServletResponse response) throws ServletException, IOException {
23 processError(request, response);
24 }
25
26 private void processError(HttpServletRequest request,
27 HttpServletResponse response) throws IOException {
28 // Analyze the servlet exception
29 Throwable throwable = (Throwable) request
30 .getAttribute("javax.servlet.error.exception");
31 Integer statusCode = (Integer) request
32 .getAttribute("javax.servlet.error.status_code");
33 String servletName = (String) request
34 .getAttribute("javax.servlet.error.servlet_name");
35 if (servletName == null) {
36 servletName = "Unknown";
37 }
38 String requestUri = (String) request
39 .getAttribute("javax.servlet.error.request_uri");
40 if (requestUri == null) {
41 requestUri = "Unknown";
42 }
43
44 // Set response content type
45 response.setContentType("text/html");
46
47 PrintWriter out = response.getWriter();
48 out.write("<html><head><title>Exception/Error Details</title></head><body>");
49 if(statusCode != 500){
50 out.write("<h3>Error Details</h3>");
51 out.write("<strong>Status Code</strong>:"+statusCode+"<br>");
52 out.write("<strong>Requested URI</strong>:"+requestUri);
53 }else{
54 out.write("<h3>Exception Details</h3>");
55 out.write("<ul><li>Servlet Name:"+servletName+"</li>");
56 out.write("<li>Exception Name:"+throwable.getClass().getName()+"</li>");
57 out.write("<li>Requested URI:"+requestUri+"</li>");
58 out.write("<li>Exception Message:"+throwable.getMessage()+"</li>");
59 out.write("</ul>");
60 }
61
62 out.write("<br><br>");
63 out.write("<a href=\"index.html\">Home Page</a>");
64 out.write("</body></html>");
65 }
66}
让我们看看如何在部署描述器中配置它,然后我们将了解它的实现以及它如何工作。
1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3 <display-name>ServletExceptionHandling</display-name>
4 <welcome-file-list>
5 <welcome-file>index.html</welcome-file>
6 </welcome-file-list>
7
8 <error-page>
9 <error-code>404</error-code>
10 <location>/AppExceptionHandler</location>
11 </error-page>
12
13 <error-page>
14 <exception-type>javax.servlet.ServletException</exception-type>
15 <location>/AppExceptionHandler</location>
16 </error-page>
17</web-app>
As you can see, it's very easy to specify Exception handler servlets for the application using error-page element. Each error-page element should have either error-code or exception-type element. We define the exception handler servlet in location element. Based on above configuration, if the application throw 404 error or ServletException, it will be handled by AppExceptionHandler servlet. When such exception and error scenario appears, servlet container will invoke the corresponding HTTP method of the Exception Handler servlet and pass the request and response object. Notice that I have provided implementation of both doGet() and doPost() methods so that it can handle GET and POST requests and using a common method to process them. Before servlet container invokes the servlet to handle the exception, it sets some attributes in the request to get useful information about the exception, some of them are javax.servlet.error.exception, javax.servlet.error.status_code, javax.servlet.error.servlet_name and javax.servlet.error.request_uri. For exception, status code is always 500 that corresponds to the "Internal Server Error", for other types of error we get different error codes such as 404, 403 etc. Using the status code, our implementation presents different types of HTML response to the user. It also provides a hyperlink to the home page of the application. Now when we will hit our servlet that is throwing ServletException, we will get a response like below image. If we try to access an invalid URL that will result in 404 response, we will get response like below image.
Doesn't it look good and helps user to easily understand what happened and provides them a way to go to the correct location. It also avoids sending application sensitive information to the user. We should always have exception handlers in place for our web application. If you want to handle runtime exceptions and all other exceptions in a single exception handler, you can provide exception-type as Throwable.
1<error-page>
2 <exception-type>java.lang.Throwable</exception-type>
3 <location>/AppExceptionHandler</location>
4</error-page>
如果有多个错误页面条目,让我们说一个为投掷和一个为IOException和应用程序投掷FileNotFoundException然后它将由IOException的错误处理处理处理。你也可以使用JSP页面作为例外处理器,只是提供JSP文件的位置而不是Servlet地图。
[下载《服务器例外处理案例》(LINK0)]
查看本系列的其他文章:
- Java Web Application File
- [Java Servlet Tutorial-servlet-servlet-url-rewriting]
- [Servlet Filter](社区/Java Servlet Tutorial with Examples for Beginners)
- Java Servlet Filter Example Management in Java
- [Servlet Filter](社区/Java Servlet Tutorial with Examples for Beg