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

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

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

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

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

  • המערכת של foobar.com תקבל הודעה מה-NEL collector
  • לא מתקבלת התראה למאסף ה-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}`);
});

קריאה נוספת