مقدمة
"تسجيل أخطاء الشبكة" (NEL) هو آلية لجمع أخطاء الشبكة من جهة العميل من مصدر معيّن.
تستخدم هذه الميزة عنوان استجابة HTTP NEL لإعلام المتصفّح بجمع أخطاء الشبكة، ثم تتكامل مع Reporting API لإبلاغ الخادم بالأخطاء.
نظرة عامة على Reporting API القديمة
عنوان Report-To القديم
لاستخدام 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 |
Array<Object> | مَعلمة مطلوبة. مصفوفة من عناصر JSON التي تحدّد عنوان URL الفعلي لجامع التقارير. |
include_subdomains |
قيمة منطقية | اختيارية: قيمة منطقية تفعّل مجموعة نقاط النهاية لجميع النطاقات الفرعية لمضيف المصدر الحالي. وفي حال حذفها أو ضبطها على أي قيمة أخرى غير "صحيح"، لن يتم إبلاغ نقطة النهاية بالنطاقات الفرعية. |
اسم 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/. هذه الصفحة مفيدة للتحقق من تكوين الأشياء بشكل صحيح وإرسال التقارير بشكل صحيح.
ماذا عن 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}`);
});