Fehlerbehandlung
In diesem Thema wollen wir uns damit beschäftigen, wie Sie in Java-Webanwendungen HTTP- und Ausnahme-Fehler abfangen können, um somit z. B. Ihren Besuchern beim Auftreten eines Fehlers, eine eigene Fehlerseite anzeigen zu können (und nicht die Standardseiten von Ihrem Webserver). Natürlich können Sie diese Möglichkeit auch dazu verwenden, Fehler zu protokollieren.
HTTP-Fehler
Im Protokoll HTTP (und auch bei HTTPS) sind sogenannte Statuscodes implementiert. Bei jeder HTTP-Antwort sendet der
Server an den Client einen solchen Statuscode mit. In den meisten Fällen wir der Code 200 OK
zurückgeschickt,
welcher signalisiert, dass die angefragte Ressource gefunden wurde und der Inhalt zurückgeschickt wird. Die Liste der
verfügbaren Statuscodes ist lang, weshalb wir uns hier vorerst mal nur mit den Statuscodes 403 Forbidden
und
404 Not Found
auseinandersetzen wollen. Der Code 403 weist darauf hin, dass der Zugriff auf die Ressource auf
Grund einer fehlenden Berechtigung nicht möglich ist. Einen solchen Fehlercode könnten Sie bspw. in einem Filter
zurückgeben, wenn ein Zugriff auf den Admin-Bereich vorgenommen wird, jedoch nicht der Administrator angemeldet ist. Den
Statuscode 404 hat vermutlich schon jeder gesehen und besagt einfach nur, dass die angefragte Ressource nicht (mehr)
verfügbar ist. Im Internet sind u. a. oftmals Links zu finden, welche auf eine Seite verweisen, welche nicht mehr
existiert. So ein Link wird dann auch als toter Link bezeichnet.
Zurück zu den Java-Webanwendungen: Wenn Sie beim Auftreten eines bestimmten Statuscodes auf eine bestimmte Seite (dabei
kann es sich auch um ein Servlet handeln) verweisen wollen, dann müssen Sie lediglich eine Konfiguration im Deployment
Descriptor durchführen. Dafür benötigen Sie das XML-Element error-page
, welchem Sie die XML-Elemente
error-code
und location
unterordnen. Dies sieht dann z. B. so aus:
<error-page> <error-code>404</error-code> <location>/ErrorServlet</location> </error-page>
Innerhalb eines Servlets können Sie mit der Funktion getAttribute()
des HttpServletRequest
-Objekts
den „fehlerhaften“ Statuscode abrufen. Als Attribut-Name müssen Sie javax.servlet.error.status_code
übergeben.
Beim Aufrufen des folgenden Beispiels werden Sie als erstes auf das Servlet ErrorServlet
umgeleitet, da es kein
Servlet für das Wurzelverzeichnis gibt. Es handelt sich daher also um einen 404-Fehler. Beim Versuch des Aufrufs von
AdminServlet
werden Sie ebenfalls wieder auf ErrorServlet
umgeleitet. Dieses Mal wird Ihnen jedoch
der Fehlercode 403 angezeigt.
Servlet (ErrorServlet.java):
package de.hwh.bsp.httpfehler; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ErrorServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Ausgabe als Text-Datei response.setContentType("text/plain;charset=UTF-8"); // Ausgabe durchführen PrintWriter out = response.getWriter(); out.println("HTTP-Fehler-Code: " + request.getAttribute("javax.servlet.error.status_code")); out.close(); } }
Servlet (AdminServlet.java):
package de.hwh.bsp.httpfehler; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AdminServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.sendError(403); } }
Konfiguration (web.xml):
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <servlet> <servlet-name>ErrorServlet</servlet-name> <servlet-class>de.hwh.bsp.httpfehler.ErrorServlet</servlet-class> </servlet> <servlet> <servlet-name>AdminServlet</servlet-name> <servlet-class>de.hwh.bsp.httpfehler.AdminServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ErrorServlet</servlet-name> <url-pattern>/ErrorServlet</url-pattern> </servlet-mapping> <error-page> <error-code>403</error-code> <location>/ErrorServlet</location> </error-page> <error-page> <error-code>404</error-code> <location>/ErrorServlet</location> </error-page> <servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/AdminServlet</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>
Übrigens: Ein weiterer gängiger Statuscode ist 500 Internal Server Error
, welcher in den meisten Fällen
auf Grund einer fehlerhaften Konfiguration des Webservers erscheint.
Ausnahmefehler
In Java sollten Sie, so wie in anderen Programmiersprachen auch, versuchen, Fehler (vor allem Ausnahmefehler) im Programm so gut wie möglich abzufangen. Trotzdem kommt es immer wieder vor, dass Sie vergessen, einen Ausnahmefehler (engl. exception) abzufangen. Dies ist auch nicht weiter schlimm, da vom Servlet-Container alle Ausnahmen abgefangen werden. Da in der Regel in so einem Fall jedoch eine Art von Debug-Informationen angezeigt werden, welche die Besucher nicht sehen sollten, sollten diese Art von Fehlern ebenfalls abgefangen werden. Auch hier kann dazu der Deployment Descriptor verwendet werden.
Im Deployment Descriptor wird auch hier das XML-Element error-page
verwendet. Diesem wird nun das
exception-type
- und das bereits bekannte location
-Element untergeordnet.
<error-page> <exception-type>java.io.IOException</exception-type> <location>/ErrorServlet</location> </error-page>
Im „Fehler-Servlet“ können wir mit der Funktion getAttribute()
und dem Attributnamen javax.servlet.error.exception_type
den Typ der Ausnahme abfragen. Mit dem Attribut javax.servlet.error.message
kann die übergebene Meldung
abgefragt werden.
Im folgenden Beispiel wird auf der Startseite (StartServlet.java
) manuell (und lediglich zu Demonstrationszwecken)
eine IO-Ausnahme (IOException
) geworfen. Dadurch leitet uns der Servlet-Container auf das Servlet ErrorServlet
um, in welchem die Informationen zur Ausnahme angezeigt werden.
Servlet (ErrorServlet.java):
package de.hwh.bsp.ausnahmefehler; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ErrorServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Ausgabe als Text-Datei response.setContentType("text/plain;charset=UTF-8"); // Ausgabe durchführen PrintWriter out = response.getWriter(); out.println("Exception-Typ: " + request.getAttribute("javax.servlet.error.exception_type")); out.println("Meldung: " + request.getAttribute("javax.servlet.error.message")); out.close(); } }
Servlet (StartServlet.java):
package de.hwh.bsp.ausnahmefehler; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class StartServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { throw new IOException("Fehler beim Zugriff auf die Ressource"); } }
Konfiguration (web.xml):
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <servlet> <servlet-name>ErrorServlet</servlet-name> <servlet-class>de.hwh.bsp.ausnahmefehler.ErrorServlet</servlet-class> </servlet> <servlet> <servlet-name>StartServlet</servlet-name> <servlet-class>de.hwh.bsp.ausnahmefehler.StartServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ErrorServlet</servlet-name> <url-pattern>/ErrorServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>StartServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <error-page> <exception-type>java.io.IOException</exception-type> <location>/ErrorServlet</location> </error-page> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>