היום נסתכל על יוצא מן הכלל של הוצאת יוצא חריגה וטיפול בשגיאות. לפני זמן קצר כתבתי פוסט על טיפול בחריגות ב-Java אך כאשר מדובר ביישום אינטרנטי, אנו זקוקים ליותר מטיפול רגיל בחריגות ב-Java.
יוצא של Servlet
אם תשימו לב, שיטות doGet() ו doPost() מזרימות javax.servlet.ServletException
ו-IOException
, בואו נראה מה קורה כאשר אנו זורקים את החריגות הללו מהיישום שלנו. אכתוב סרבל פשוט שיזרוק את ה- ServletException.
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, אנו מקבלים תגובה כמו בתמונה למטה. מאחר ודפדפן מבין רק HTML, כאשר היישום שלנו זורק חריגה, תיבת הסרבל מעבדת את החריגה ויוצרת תגובת HTML. הלוגיקה הזו היא ספציפית לתיבת הסרבל. אני משתמש ב- Tomcat ומקבל את דף השגיאה הזה. אם תשתמשו בשרתים אחרים כמו JBoss או Glassfish, ייתכן שתקבלו תגובת HTML שונה לשגיאה. הבעיה עם התגובה הזו היא שאין לה שום ערך למשתמש. גם היא מציגה את כיתות היישום שלנו ופרטי השרת למשתמש, מה שאין לו שום משמעות למשתמש וזה לא טוב מנקודת מבט האבטחה.
שגיאת סרבל
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 מספק תמיכה בסרבלים מותאמים אישית עבור יוצאים מן הכלל וטיפול בשגיאות שניתקבלו. אתרכה מטרתם של סרבלים אלה היא לטפל בשגיאה או שגיאה שנגרמה על ידי היישום ולשלוח תגובת HTML שימושית למשתמש. ניתן לספק קישור לדף הבית של היישום או פרטים מסוימים כדי להודיע למשתמש מה השתבש. לכן, לפני הכל, עלינו ליצור סרבל טיפול בשגיאות ושגיאות מותאם אישית. ניתן להכיל מספר סרבלים של טיפול בשגיאות ושגיאות עבור היישום, אך מסיבות פשטות אני אצור סרבל יחיד ואשתמש בו עבור שני היצאים והשגיאות. 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 {
// נבחן את החריגה של הסרבל
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. כל אלמנט error-page צריך לכלול או אלמנט error-code או exception-type. אנו מגדירים את סרבל מטפל החריגה באלמנט 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, נקבל תגובה כמו בתמונה למטה. אם ננסה לגשת לכתובת URL לא חוקית שתגרום לתגובת 404, נקבל תגובה כמו בתמונה למטה.
האם זה נראה טוב ועוזר למשתמש להבין בקלות מה קרה ומספק להם דרך להגיע למיקום הנכון? זה גם מונע את שליחת מידע רגיש של היישום למשתמש. תמיד עלינו להקפיד על מטפלי חריגות במקום עבור היישום שלנו. אם ברצונך לטפל בחריגות הרצת זמן ובכל החריגות האחרות במטפל חריגה יחיד, תוכל לספק את סוג החריגה כ-Throwable.
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
אם ישנם מספר רב של ערכי דפי שגיאה, נניח אחד עבור Throwable ואחד עבור IOException והיישום זורק FileNotFoundException, אז זה ייטפל על ידי עובדת השגיאה של IOException. ניתן גם להשתמש בדף JSP כגורם יוצא דופן, פשוט ציין את מיקום קובץ ה-JSP במקום ציון עקיפת שרת. זהו כל הדברים בניהול חריגות שרת ביישום האינטרנט, אני מקווה שאהבת את זה.
הורד דוגמת פרויקט לניהול חריגת סרבלט
בדוק את המאמרים האחרים בסדרה זו: