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

مقدمة

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

وهو يستخدم عنوان استجابة HTTP NEL ليطلب من المتصفّح جمع أخطاء الشبكة، ثم يتكامل مع Reporting API من أجل إبلاغ الخادم بالأخطاء.

نظرة عامة على Reporting API القديمة

لاستخدام Reporting API القديمة، عليك ضبط عنوان استجابة Report-To HTTP. وقيمتها هي عنصر يصف مجموعة نقاط نهاية للمتصفّح لإبلاغ عن الأخطاء إلى:

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

اسم group هو اسم فريد يُستخدَم لربط سلسلة بنقطة نهاية. استخدِم هذا الاسم في أماكن أخرى يمكن دمجها مع Reporting API للإشارة إلى مجموعة نقاط نهاية محدّدة.

الحقل max-age مطلوب أيضًا ويحدّد المدّة التي يجب أن يستخدم فيها المتصفّح نقطة النهاية ويبلّغها بالأخطاء.

الحقل endpoints هو مصفوفة لتوفير ميزات تجاوز الأعطال وموازنة التحميل. اطّلِع على القسم المعنيّ بالتبديل عند حدوث خطأ وموازنة التحميل. يُرجى العِلم أنّ المتصفّح سيختار نقطة نهاية واحدة فقط، حتى إذا كانت المجموعة تسرد عدة أدوات جمع في endpoints. إذا كنت تريد إرسال ملف ملف إحصاءات إلى عدة خوادم في آنٍ واحد، يجب أن تعيد توجيه ملف الإحصاءات من خلال الخلفية.

كيف يرسل المتصفّح التقارير؟

يُجمِّع المتصفّح التقارير بشكل دوري ويرسلها إلى نقاط نهاية reporting التي تحدّدها.

لإرسال التقارير، يُرسِل المتصفّح 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 وتعذّر loadingتحميل هذا المورد:

  • يتم إشعار جامع 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}`);
});

مراجع إضافية