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

מבוא

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

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

סקירה כללית של הגרסה הקודמת של Reporting API

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

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 לאחר מכן שנשלחו על ידי הדף (לתמונות, סקריפטים וכו') המערכת מתעלמת ממנו. ההגדרה מתבצעת במהלך התשובה של הדף הראשי.

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

כל הגדרה של נקודת קצה מכילה את השם 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. אם רוצים לשלוח לדווח לכמה שרתים בבת אחת, הקצה העורפי שלכם יצטרך להעביר את דוחות.

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

הדפדפן מקבץ מדי פעם דוחות ושולח אותם לדוחות נקודות הקצה (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 לכל קבוצה. אבל, לפעמים מאחר שהדיווח יכול ליצור תנועה רבה, המפרט כולל יתירות כשל ותכונות של איזון עומסים בהשראת ה-DNS רשומת SRV.

הדפדפן יעשה כמיטב יכולתו כדי לספק דוח לנקודת קצה אחת לכל היותר. בקבוצה. אפשר להקצות לנקודות קצה (endpoint) weight כדי לפזר את העומס, נקודת הקצה שמקבלת חלק מסוים של התנועה שמדווחת. נקודות הקצה יכולות יוקצה גם 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 שלו, וגם אין לו גישה לדוחות ה-NEL שלו.

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

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

מה לגבי ReportingObserver?

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

שרת לדוגמה

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

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}`);
});

קריאה נוספת