ثبت خطای شبکه (NEL)

مقدمه

ثبت خطاهای شبکه (NEL) مکانیزمی برای جمع‌آوری خطاهای شبکه سمت کلاینت از مبدا است.

این ابزار از هدر پاسخ NEL HTTP برای اعلام جمع‌آوری خطاهای شبکه به مرورگر استفاده می‌کند، سپس با Reporting API ادغام می‌شود تا خطاها را به سرور گزارش دهد.

مروری بر API گزارش‌دهی قدیمی

برای استفاده از گزارش‌دهی 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 ).

در مثال، ارسال این هدر پاسخ به همراه صفحه اصلی، مرورگر را طوری پیکربندی می‌کند که هشدارهای تولید شده توسط مرورگر را به مدت max_age ثانیه به نقطه پایانی https://analytics.provider.com/browser-errors گزارش دهد. توجه به این نکته مهم است که تمام درخواست‌های HTTP بعدی که توسط صفحه ارسال می‌شوند (برای تصاویر، اسکریپت‌ها و غیره) نادیده گرفته می‌شوند. پیکربندی در طول پاسخ صفحه اصلی تنظیم می‌شود.

توضیح فیلدهای هدر

هر پیکربندی نقطه پایانی شامل یک نام group ، max_age و آرایه endpoints است. همچنین می‌توانید با استفاده از فیلد include_subdomains انتخاب کنید که آیا هنگام گزارش خطاها، زیر دامنه‌ها را نیز در نظر بگیرید یا خیر.

میدان نوع توضیحات
group رشته اختیاری. اگر نام group مشخص نشود، به نقطه پایانی نام "پیش‌فرض" داده می‌شود.
max_age شماره الزامی . یک عدد صحیح غیر منفی که طول عمر نقطه پایانی را بر حسب ثانیه تعریف می‌کند. مقدار "0" باعث می‌شود گروه نقطه پایانی از حافظه پنهان گزارش‌دهی عامل کاربر حذف شود.
endpoints آرایه <Object> الزامی . آرایه‌ای از اشیاء JSON که URL واقعی گردآورنده گزارش شما را مشخص می‌کند.
include_subdomains بولی اختیاری. یک مقدار بولی که گروه نقطه پایانی را برای همه زیر دامنه‌های میزبان مبدا فعلی فعال می‌کند. اگر حذف شود یا هر مقدار دیگری غیر از "true" باشد، زیر دامنه‌ها به نقطه پایانی گزارش نمی‌شوند.

نام group ، نامی منحصر به فرد است که برای مرتبط کردن یک رشته با یک نقطه پایانی استفاده می‌شود. از این نام در جاهای دیگری که با Reporting API ادغام می‌شوند، برای اشاره به یک گروه نقطه پایانی خاص استفاده کنید.

فیلد max-age نیز الزامی است و مشخص می‌کند که مرورگر تا چه مدت باید از نقطه پایانی استفاده کند و خطاها را به آن گزارش دهد.

فیلد endpoints یک آرایه برای ارائه ویژگی‌های failover و load balancing است. به بخش failover و load balancing مراجعه کنید. توجه به این نکته مهم است که مرورگر فقط یک نقطه پایانی را انتخاب می‌کند ، حتی اگر گروه چندین جمع‌کننده را در endpoints فهرست کند. اگر می‌خواهید گزارشی را به طور همزمان به چندین سرور ارسال کنید، backend شما باید گزارش‌ها را ارسال کند.

مرورگر چگونه گزارش‌ها را ارسال می‌کند؟

مرورگر به صورت دوره‌ای گزارش‌ها را دسته‌بندی کرده و آنها را به نقاط پایانی گزارش‌دهی که شما پیکربندی می‌کنید، ارسال می‌کند.

برای ارسال گزارش‌ها، مرورگر یک درخواست 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 را برای هر گروه پیکربندی می‌کنید. با این حال، از آنجایی که گزارش‌گیری می‌تواند ترافیک زیادی ایجاد کند، این مشخصات شامل ویژگی‌های failover و load-balancing است که از رکورد DNS 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 یک مکانیزم گزارش‌دهی مرتبط اما متفاوت است. این مکانیزم مبتنی بر فراخوانی‌های جاوا اسکریپت است. برای ثبت خطاهای شبکه مناسب نیست ، زیرا خطاهای شبکه را نمی‌توان از طریق جاوا اسکریپت رهگیری کرد.

سرور نمونه

در زیر یک نمونه سرور 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}`);
});

مطالعه بیشتر