Введение
Network Error Logging (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 |
string | Необязательное поле. Если имя group не указано, конечной точке присваивается имя default. |
max_age |
число | Обязательный параметр. Неотрицательное целое число, определяющее время жизни конечной точки в секундах. Если указать значение "0", группа конечных точек будет удалена из кеша отчетов агента пользователя. |
endpoints |
Array<Object> | Обязательный параметр. Массив объектов JSON, в которых указан фактический URL сборщика отчетов. |
include_subdomains |
Логическое значение | Необязательное поле. Логическое значение, которое включает группу конечных точек для всех субдоменов хоста текущего источника. Если параметр опущен или имеет значение, отличное от true, субдомены не передаются конечной точке. |
Название 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 DNS.
Браузер попытается отправить отчет не более чем одной конечной точке в группе. Конечным точкам можно назначить 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}`);
});