Регистрация сетевых ошибок (NEL)

Введение

Журналирование сетевых ошибок (Network Error Logging, NEL) — это механизм сбора сетевых ошибок на стороне клиента, возникающих в источнике.

Он использует заголовок HTTP-ответа NEL , чтобы сообщить браузеру о необходимости сбора сетевых ошибок, а затем интегрируется с 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 ).

В приведенном примере отправка этого заголовка ответа вместе с вашей главной страницей настраивает браузер на отправку сгенерированных браузером предупреждений на конечную точку https://analytics.provider.com/browser-errors в течение max_age секунд. Важно отметить, что все последующие HTTP-запросы, выполняемые страницей (для изображений, скриптов и т. д.), игнорируются. Конфигурация устанавливается во время отправки ответа от главной страницы.

Пояснение к полям заголовка

Каждая конфигурация конечной точки содержит имя group , max_age и массив endpoints . Вы также можете выбрать, следует ли учитывать поддомены при сообщении об ошибках, используя поле include_subdomains .

Поле Тип Описание
group нить Необязательно. Если имя group не указано, конечной точке присваивается имя "default".
max_age число Обязательное значение . Неотрицательное целое число, определяющее время жизни конечной точки в секундах. Значение «0» приведет к удалению группы конечных точек из кэша отчетов пользовательского агента.
endpoints Массив<Объект> Обязательный параметр . Массив JSON-объектов, указывающих фактический URL-адрес вашего сборщика отчетов.
include_subdomains логический Необязательный параметр. Логическое значение, которое включает группу конечных точек для всех поддоменов хоста текущего источника. Если параметр опущен или имеет значение, отличное от «true», поддомены не передаются на конечную точку.

Имя group — это уникальное имя, используемое для связывания строки с конечной точкой. Используйте это имя в других местах, интегрированных с API отчетов, для ссылки на конкретную группу конечных точек.

Поле max-age также является обязательным и указывает, как долго браузер должен использовать конечную точку и сообщать ей об ошибках.

Поле endpoints представляет собой массив, обеспечивающий функции отказоустойчивости и балансировки нагрузки. См. раздел « Отказоустойчивость и балансировка нагрузки» . Важно отметить, что браузер выберет только одну конечную точку , даже если в группе endpoints указано несколько сборщиков данных. Если вы хотите отправить отчет на несколько серверов одновременно, ваш бэкэнд должен будет перенаправлять отчеты.

Как браузер отправляет отчеты?

Браузер периодически формирует пакеты отчетов и отправляет их на настроенные вами конечные точки для формирования отчетов.

Для отправки отчетов браузер отправляет POST запрос с Content-Type: application/reports+json и телом, содержащим массив предупреждений/ошибок, которые были зафиксированы.

Когда браузер отправляет отчеты?

Отчеты передаются из вашего приложения внеполосным способом , то есть браузер контролирует, когда отчеты отправляются на ваш(и) сервер(ы).

Браузер пытается доставить отчеты из очереди в наиболее подходящее время. Это может быть сразу после их готовности (для своевременной обратной связи с разработчиком), но браузер также может задержать доставку, если он занят обработкой более приоритетных задач или если пользователь в это время находится в медленной и/или перегруженной сети. Браузер также может отдавать приоритет отправке отчетов о конкретном источнике, если пользователь является частым посетителем.

При использовании 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-адресов на группу. Однако, поскольку формирование отчетов может генерировать значительный трафик, спецификация включает функции отказоустойчивости и балансировки нагрузки, вдохновленные записью 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 — это связанный, но отличающийся механизм формирования отчетов. Он основан на вызовах 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}`);
});

Дополнительная информация