تسجيل خطأ في الشبكة (NEL)

مود نالباس
مود ناالبا

مقدمة

تسجيل أخطاء الشبكة (NEL) هو آلية لجمع أخطاء الشبكة من جهة العميل من المصدر.

تستخدِم هذه السياسة عنوان استجابة HTTP NEL لإبلاغ المتصفِّح بجمع أخطاء الشبكة، ثم يتكامل مع 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، يتم تخصيص اسم "تلقائي" لنقطة النهاية.
max_age الرقم مَعلمة مطلوبة. عدد صحيح غير سالب يحدّد عمر نقطة النهاية بالثواني. ستؤدي القيمة "0" إلى إزالة مجموعة نقاط النهاية من ذاكرة التخزين المؤقت لإعداد تقارير وكيل المستخدم.
endpoints مصفوفة<Object> مَعلمة مطلوبة. مصفوفة من كائنات JSON التي تحدّد عنوان URL الفعلي لأداة تجميع التقارير.
include_subdomains boolean اختياريّ. يشير ذلك المصطلح إلى قيمة منطقية تُفعِّل مجموعة نقاط النهاية لجميع النطاقات الفرعية لمضيف المصدر الحالي. أما في حال حذفها أو إدخال أي قيمة أخرى غير "صحيح"، فلن يتم الإبلاغ عن النطاقات الفرعية في نقطة النهاية.

اسم 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 لنظام أسماء النطاقات.

سيبذل المتصفّح قصارى جهده لإرسال تقرير إلى نقطة نهاية واحدة على الأكثر في المجموعة. يمكن تخصيص 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 الخاصة به أيضًا.

إعدادات تقارير تصحيح الأخطاء

إذا لم تظهر لك تقارير على الخادم، انتقِل إلى chrome://net-export/. هذه الصفحة مفيدة للتحقق من تهيئة الأشياء بشكل صحيح وإرسال التقارير بشكل صحيح.

ماذا عن ReportingMonitorer؟

ReportingObserver هي آلية إبلاغ مرتبطة ببعضها، ولكنها مختلفة. وهو يعتمد على طلبات JavaScript. ولا يصلح لتسجيل أخطاء الشبكة، حيث لا يمكن اعتراض أخطاء الشبكة عبر JavaScript.

مثال على خادم

فيما يلي مثال على خادم عقدة يستخدم 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}`);
});

محتوى إضافي للقراءة