Статьи

Учебное пособие по исключениям и обработке ошибок сервлета

Некоторое время назад я написал пост об обработке исключений в Java, но когда дело доходит до веб-приложения, нам нужно больше, чем обычная обработка исключений в Java.

Сервлет Исключение

Если вы заметили, что методы doGet () и doPost () ServletException и IOException , давайте посмотрим, что произойдет, когда мы выбросим эти исключения из нашего приложения. Я напишу простой сервлет, который выдаст исключение ServletException.

MyExceptionServlet.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
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-Exception-User

Поскольку браузер понимает только HTML, когда наше приложение генерирует исключение, контейнер сервлета обрабатывает исключение и генерирует HTML-ответ. Эта логика специфична для контейнера сервлетов, я использую tomcat и получаю эту страницу с ошибкой, но если вы будете использовать некоторые другие серверы, такие как JBoss или Glassfish, вы можете получить другой HTML-ответ об ошибке.

Проблема с этим ответом заключается в том, что он не имеет значения для пользователя. Кроме того, он показывает пользователям наши классы приложений и информацию о сервере, что не имеет смысла для пользователя и не очень хорошо с точки зрения безопасности.

Ошибка сервлета

Я уверен, что вы, должно быть, увидели ошибку 404, когда пытались найти URL, который не существует. Давайте посмотрим, как наш контейнер сервлетов отвечает на ошибку 404. Если мы отправим запрос на неверный URL, мы получим ответ HTML, как показано на рисунке ниже.

Сервлет-404-Ошибка

Опять же, это общий HTML-код, сгенерированный сервером от нашего имени и не имеющий никакой ценности для пользователя.

Исключение сервлета и обработка ошибок

Servlet API обеспечивает поддержку настраиваемых сервлетов Exception и Error Handler, которые мы можем настроить в дескрипторе развертывания. Целью этих сервлетов является обработка Exception или Error, возникающих в приложении, и отправка HTML-ответа, который будет полезен для пользователя. Мы можем предоставить ссылку на домашнюю страницу приложения или некоторые детали, чтобы сообщить пользователю, что пошло не так.

Поэтому прежде всего нам нужно создать собственный сервлет Exception and Error Handler. У нас может быть несколько сервлетов обработки исключений и ошибок для приложения, но для простоты я создам один сервлет и использую его как для исключений, так и для ошибок.

AppExceptionHandler.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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 {
        // 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>");
    }
}

Давайте посмотрим, как мы можем настроить его в дескрипторе развертывания, и тогда мы поймем его реализацию и как это работает.

web.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
  <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 . Каждый элемент страницы ошибки должен иметь либо код ошибки, либо элемент типа исключения . Мы определяем сервлет обработчика исключений в элементе location .

Исходя из описанной выше конфигурации, если приложение выдает ошибку 404 или ServletException, оно будет обработано сервлетом AppExceptionHandler.

Когда появляется такой сценарий исключения и ошибки, контейнер сервлета вызовет соответствующий метод HTTP сервлета обработчика исключений и передаст объект запроса и ответа. Обратите внимание, что я предоставил реализацию методов doGet () и doPost (), чтобы он мог обрабатывать запросы GET и POST и использовать общий метод для их обработки.

Прежде чем контейнер сервлета вызывает сервлет для обработки исключения, он устанавливает некоторые атрибуты в запросе, чтобы получить полезную информацию об исключении, некоторые из них — 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-обработки исключений-500-Code

Если мы попытаемся получить доступ к неверному URL-адресу, который приведет к ответу 404, мы получим ответ, как показано на рисунке ниже.

Servlet-Error-Handling-404

Разве это не выглядит хорошо и помогает пользователю легко понять, что произошло, и дает им возможность перейти в правильное место. Это также позволяет избежать отправки конфиденциальной информации приложения пользователю. У нас всегда должны быть обработчики исключений для нашего веб-приложения.

Если вы хотите обрабатывать исключения во время выполнения и все другие исключения в одном обработчике исключений, вы можете предоставить тип исключения как Throwable.

1
2
3
4
<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/AppExceptionHandler</location>
</error-page>

Если имеется несколько записей на странице ошибок, скажем, одна для Throwable и одна для IOException, и приложение выдает FileNotFoundException, то это будет обработано обработчиком ошибок IOException.

Вы также можете использовать страницу JSP в качестве обработчика исключений, просто указав расположение файла jsp, а не отображение сервлета.

Это все для обработки исключений в веб-приложении, надеюсь, вам понравилось.