רישום שגיאות ברשת (NEL)

מבוא

רישום שגיאות ברשת (NEL) הוא מנגנון לאיסוף שגיאות ברשת בצד הלקוח ממקור.

היא משתמשת בכותרת התגובה NEL של ה-HTTP כדי להנחות את הדפדפן לאסוף שגיאות רשת, ואז משתלבת עם Reporting API כדי לדווח על השגיאות לשרת.

סקירה כללית על Reporting API הקודם

כדי להשתמש ב-Reporting API הקודם, צריך להגדיר כותרת תגובה של HTTP‏ Report-To. הערך שלו הוא אובייקט שמתאר קבוצת נקודות קצה (endpoint) שבהן הדפדפן יכול לדווח על שגיאות:

Report-To:
{
    "max_age": 10886400,
    "endpoints": [{
    "url": "https://analytics.provider.com/browser-errors"
    }]
}

אם כתובת ה-URL של נקודת הקצה נמצאת במקור אחר מאשר האתר שלכם, נקודת הקצה צריכה לתמוך בבקשות CORS לבדיקה מראש. (למשל, Access-Control-Allow-Origin: *; Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS; Access-Control-Allow-Headers: Content-Type, Authorization, Content-Length, X-Requested-With).

בדוגמה הזו, שליחת כותרת התגובה הזו עם הדף הראשי מגדירה את הדפדפן לדווח על אזהרות שנוצרו בדפדפן לנקודת הקצה https://analytics.provider.com/browser-errors למשך max_age שניות. חשוב לציין שכל בקשות ה-HTTP הבאות שהדף שולח (לתמונות, ל-scripts וכו') מתעלמות. ההגדרה מתבצעת במהלך התגובה של הדף הראשי.

הסבר על שדות הכותרת

כל הגדרה של נקודת קצה מכילה את המערך group, max_age ו-endpoints. בעזרת השדה include_subdomains אפשר גם לבחור אם להביא בחשבון תת-דומיינים כשמדווחים על שגיאות.

שדה סוג תיאור
group מחרוזת זה שינוי אופציונלי. אם לא מציינים שם של group, נקרא לנקודת הקצה 'default'.
max_age number נדרש. מספר שלם לא שלילי שמגדיר את משך החיים של נקודת הקצה בשניות. הערך '0' יגרום להסרת קבוצת נקודות הקצה מהמטמון של הדיווח של סוכן המשתמש.
endpoints מערך<אובייקט> נדרש. מערך של אובייקטי JSON שמציינים את כתובת ה-URL בפועל של אוסף הדוחות.
include_subdomains בוליאני זה שינוי אופציונלי. ערך בוליאני שמפעיל את הקבוצה של נקודות הקצה בכל תתי-הדומיין של המארח של המקור הנוכחי. אם השדה הזה לא יצוין או יצוין בו ערך שאינו 'true', תת-הדומיינים לא ידווחו לנקודת הקצה.

השם group הוא שם ייחודי שמשמש לשיוך מחרוזת לנקודת קצה. כדאי להשתמש בשם הזה במקומות אחרים שמשתלבים עם Reporting API כדי להתייחס לקבוצה ספציפית של נקודות קצה.

גם השדה max-age נדרש, והוא מציין למשך כמה זמן הדפדפן ישתמש בנקודת הקצה וידווח על שגיאות אליה.

השדה endpoints הוא מערך שמספק תכונות של חלוקת עומסים ויתירות. מידע נוסף זמין בקטע מעבר לגיבוי ואיזון עומסים. חשוב לציין שהדפדפן יבחר רק נקודת קצה אחת, גם אם בקבוצה יש מספר אספנים ב-endpoints. אם רוצים לשלוח דוח לכמה שרתים בו-זמנית, הקצה העורפי צריך להעביר את הדוחות.

איך הדפדפן שולח דוחות?

הדפדפן אוסף מדי פעם דוחות בקבוצות ושולח אותם לנקודות הקצה לדיווח שהוגדרו.

כדי לשלוח דוחות, הדפדפן שולח בקשת POST עם Content-Type: application/reports+json וגוף שמכיל את מערך האזהרות או השגיאות שתועדו.

מתי הדפדפן שולח דוחות?

הדוחות נשלחים מחוץ למסגרת האפליקציה, כלומר הדפדפן קובע מתי הדוחות נשלחים לשרתים שלכם.

הדפדפן מנסה לשלוח את הדוחות שבתור בזמן המתאים ביותר. יכול להיות שהן יישלחו ברגע שהן יהיו מוכנות (כדי לספק משוב למפתח בזמן), אבל הדפדפן יכול גם לעכב את השליחה אם הוא עסוק בעיבוד משימות בעדיפות גבוהה יותר, או אם המשתמש מחובר לרשת איטית ו/או עמוסת נתונים באותו זמן. יכול להיות גם שהדפדפן ייתן עדיפות לשליחת דוחות על מקור מסוים קודם, אם המשתמש מבקר בו לעיתים קרובות.

כשמשתמשים ב-Reporting API, אין בעיות משמעותיות בביצועים (למשל, תחרות על הרשת עם האפליקציה שלכם). בנוסף, אי אפשר לקבוע מתי הדפדפן ישלח דוחות שנמצאים בתור.

הגדרת כמה נקודות קצה

בתגובה אחת אפשר להגדיר כמה נקודות קצה בבת אחת על ידי שליחת כמה כותרות Report-To:

Report-To: {
             "group": "default",
             "max_age": 10886400,
             "endpoints": [{
               "url": "https://example.com/browser-reports"
             }]
           }
Report-To: {
             "group": "network-errors-endpoint",
             "max_age": 10886400,
             "endpoints": [{
               "url": "https://example.com/network-errors"
             }]
           }

או על ידי שילובם לכותרת HTTP אחת:

Report-To: {
             "group": "network-errors-endpoint",
             "max_age": 10886400,
             "endpoints": [{
               "url": "https://example.com/network-errors"
             }]
           },
           {
             "max_age": 10886400,
             "endpoints": [{
               "url": "https://example.com/browser-errors"
             }]
           }

אחרי ששולחים את הכותרת Report-To, הדפדפן מאחסן את נקודות הקצה במטמון בהתאם לערכי max_age שלהן, ושולח את כל האזהרות או השגיאות הלא נעימות האלה במסוף לכתובות ה-URL שלכם.

חלוקת עומסים והעברה אוטומטית למצב חירום

ברוב המקרים תגדירו אוסף כתובות URL אחד לכל קבוצה. עם זאת, מאחר שדיווח יכול ליצור כמות גדולה של תנועה, המפרט כולל תכונות של חלוקת עומסים ויתירות בהשראת רשומת ה-SRV ב-DNS.

הדפדפן יעשה כמיטב יכולתו כדי לשלוח דוח לנקודת קצה (endpoint) אחת לכל היותר בקבוצה. אפשר להקצות לקצוות weight כדי לחלק את העומס, כאשר כל נקודה מקבלת חלק מסוים מתנועת הדיווח. אפשר גם להקצות לנקודות קצה (endpoint) priority כדי להגדיר אוספים חלופיים.

המערכת מנסה להשתמש במאגרי הנתונים החלופיים רק אם ההעלאות למאגרי הנתונים הראשיים נכשלות.

דוגמה: יצירת אוסף חלופות ב-https://backup.com/reports:

Report-To: {
             "group": "endpoint-1",
             "max_age": 10886400,
             "endpoints": [
               {"url": "https://example.com/reports", "priority": 1},
               {"url": "https://backup.com/reports", "priority": 2}
             ]
           }

הגדרת רישום שגיאות ברשת

הגדרה

כדי להשתמש ב-NEL, צריך להגדיר את הכותרת Report-To עם אוסף איסוף שמשתמש בקבוצה בעלת שם:

Report-To: {
    ...
  }, {
    "group": "network-errors",
    "max_age": 2592000,
    "endpoints": [{
      "url": "https://analytics.provider.com/networkerrors"
    }]
  }

בשלב הבא, צריך לשלוח את כותרת התשובה NEL כדי להתחיל לאסוף שגיאות. מכיוון ש-NEL הוא הסכמה מראש למקור, צריך לשלוח את הכותרת רק פעם אחת. גם NEL וגם Report-To יחולו על בקשות עתידיות לאותו מקור, וימשיכו לאסוף שגיאות בהתאם לערך של max_age ששימש להגדרת האוסף.

ערך הכותרת צריך להיות אובייקט JSON שמכיל את השדות max_age ו-report_to. משתמשים באפשרות השנייה כדי להפנות לשם הקבוצה של האוסף של שגיאות הרשת:

GET /index.html HTTP/1.1
NEL: {"report_to": "network-errors", "max_age": 2592000}

משאבי משנה

דוגמה: אם example.com טוען את foobar.com/cat.gif והמשאב הזה לא נטען:

  • נשלחה הודעה לקסם NEL של foobar.com
  • לא נשלחת הודעה לגבי אוסף ה-NEL של example.com

הכלל הוא ש-NEL משחזר יומנים בצד השרת שנוצרו זה עתה בצד הלקוח.

מכיוון של-example.com אין גישה ליומני השרת של foobar.com, אין לו גם גישה לדוחות ה-NEL שלו.

ניפוי באגים בהגדרות של דוחות

אם הדוחות לא מופיעים בשרת, אפשר לעבור אל chrome://net-export/. הדף הזה שימושי כדי לוודא שההגדרות נכונות והדוחות נשלחים בצורה תקינה.

מה לגבי ReportingObserver?

ReportingObserver הוא מנגנון דיווח קשור, אבל שונה. הוא מבוסס על קריאות JavaScript. היא לא מתאימה לרישום ביומן של שגיאות רשת, כי אי אפשר ליירט שגיאות רשת באמצעות JavaScript.

שרת לדוגמה

בהמשך מוצגת דוגמה לשרת Node שמשתמש ב-Express. כאן מוסבר איך מגדירים דיווח על שגיאות ברשת, וליצור טיפול ייעודי כדי לתעד את התוצאה.

const express = require('express');

const app = express();
app.use(
  express.json({
    type: ['application/json', 'application/reports+json'],
  }),
);
app.use(express.urlencoded());

app.get('/', (request, response) => {
  // Note: report_to and not report-to for NEL.
  response.set('NEL', `{"report_to": "network-errors", "max_age": 2592000}`);

  // The Report-To header tells the browser where to send network errors.
  // The default group (first example below) captures interventions and
  // deprecation reports. Other groups, like the network-error group, are referenced by their "group" name.
  response.set(
    'Report-To',
    `{
    "max_age": 2592000,
    "endpoints": [{
      "url": "https://reporting-observer-api-demo.glitch.me/reports"
    }],
  }, {
    "group": "network-errors",
    "max_age": 2592000,
    "endpoints": [{
      "url": "https://reporting-observer-api-demo.glitch.me/network-reports"
    }]
  }`,
  );

  response.sendFile('./index.html');
});

function echoReports(request, response) {
  // Record report in server logs or otherwise process results.
  for (const report of request.body) {
    console.log(report.body);
  }
  response.send(request.body);
}

app.post('/network-reports', (request, response) => {
  console.log(`${request.body.length} Network error reports:`);
  echoReports(request, response);
});

const listener = app.listen(process.env.PORT, () => {
  console.log(`Your app is listening on port ${listener.address().port}`);
});

קריאה נוספת