Registro de erros de rede (NEL, na sigla em inglês)

Introdução

O Network Error Logging (NEL) é um mecanismo para coletar erros de rede do lado do cliente de uma origem.

Ele usa o cabeçalho de resposta HTTP NEL para informar ao navegador que colete erros de rede e, em seguida, se integra à API Reporting para informar os erros a um servidor.

Visão geral da API Reporting legada

Para usar a API Reporting legada, você precisa definir um cabeçalho de resposta HTTP Report-To. O valor dele é um objeto que descreve um grupo de endpoints para o navegador informar erros:

Report-To:
{
    "max_age": 10886400,
    "endpoints": [{
    "url": "https://analytics.provider.com/browser-errors"
    }]
}

Se o URL do endpoint estiver em uma origem diferente do seu site, ele precisará oferecer suporte a solicitações de simulação do CORS. Por exemplo, 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.

No exemplo, o envio desse cabeçalho de resposta com a página principal configura o navegador para informar avisos gerados pelo navegador ao endpoint https://analytics.provider.com/browser-errors por segundos max_age. É importante observar que todas as solicitações HTTP subsequentes feitas pela página (para imagens, scripts etc.) são ignoradas. A configuração é feita durante a resposta da página principal.

Explicação dos campos de cabeçalho

Cada configuração de endpoint contém um nome group, max_age e uma matriz endpoints. Você também pode escolher se quer considerar subdomínios ao informar erros usando o campo include_subdomains.

Campo Tipo Descrição
group string Opcional. Se um nome group não for especificado, o endpoint receberá o nome "padrão".
max_age número Obrigatório. Um número inteiro não negativo que define a vida útil do endpoint em segundos. Um valor de "0" fará com que o grupo de endpoints seja removido do cache de relatórios do user agent.
endpoints Array<Object> Obrigatório. Uma matriz de objetos JSON que especifica o URL real do coletor de relatórios.
include_subdomains booleano Opcional. Um booleano que ativa o grupo de endpoints para todos os subdomínios do host da origem atual. Se omitido ou qualquer outro valor que não seja "true", os subdomínios não serão informados ao endpoint.

O nome group é um nome exclusivo usado para associar uma string a um endpoint. Use esse nome em outros lugares que se integram à API Reporting para se referir a um grupo de endpoints específico.

O campo max-age também é obrigatório e especifica por quanto tempo o navegador deve usar o endpoint e informar erros a ele.

O campo endpoints é uma matriz para fornecer recursos de failover e balanceamento de carga. Consulte a seção sobre failover e balanceamento de carga. É importante observar que o navegador vai selecionar apenas um endpoint, mesmo que o grupo liste vários coletores em endpoints. Se você quiser enviar um relatório para vários servidores de uma só vez, o back-end precisará encaminhar os relatórios.

Como o navegador envia relatórios?

O navegador agrupa periodicamente os relatórios e os envia aos endpoints de relatórios configurados.

Para enviar relatórios, o navegador emite uma solicitação POST com Content-Type: application/reports+json e um corpo contendo a matriz de avisos/erros capturados.

Quando o navegador envia relatórios?

Os relatórios são entregues fora da banda do seu app, o que significa que o navegador controla quando os relatórios são enviados aos seus servidores.

O navegador tenta entregar relatórios enfileirados no momento mais oportuno. Isso pode acontecer assim que eles estiverem prontos (para fornecer feedback oportuno ao desenvolvedor), mas o navegador também pode atrasar a entrega se estiver ocupado processando trabalhos de maior prioridade ou se o usuário estiver em uma rede lenta e/ou congestionada no momento. O navegador também pode priorizar o envio de relatórios sobre uma origem específica primeiro, se o usuário for um visitante frequente.

Há pouca ou nenhuma preocupação com a performance (por exemplo, contenção de rede com seu app) ao usar a API Reporting. Também não há como controlar quando o navegador envia relatórios enfileirados.

Como configurar vários endpoints

Uma única resposta pode configurar vários endpoints de uma só vez enviando vários cabeçalhos 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"
             }]
           }

ou combinando-os em um único cabeçalho 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"
             }]
           }

Depois de enviar o cabeçalho Report-To, o navegador armazena os endpoints em cache de acordo com os valores max_age e envia todos esses avisos/erros de console para seus URLs.

Failover e balanceamento de carga

Na maioria das vezes, você vai configurar um coletor de URL por grupo. No entanto, como a geração de relatórios pode gerar um bom tráfego, a especificação inclui recursos de failover e balanceamento de carga inspirados no registro SRV do DNS.

O navegador fará o possível para entregar um relatório a no máximo um endpoint em um grupo. Os endpoints podem receber um weight para distribuir a carga, com cada endpoint recebendo uma fração especificada do tráfego de relatórios. Os endpoints também podem receber uma priority para configurar coletores de fallback.

Os coletores de fallback só são testados quando os uploads para coletores principais falham.

Exemplo: crie um coletor de fallback em 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}
             ]
           }

Como configurar o Network Error Logging

Configuração

Para usar o NEL, configure o cabeçalho Report-To com um coletor que usa um grupo nomeado:

Report-To: {
    ...
  }, {
    "group": "network-errors",
    "max_age": 2592000,
    "endpoints": [{
      "url": "https://analytics.provider.com/networkerrors"
    }]
  }

Em seguida, envie o cabeçalho de resposta NEL para começar a coletar erros. Como o NEL é ativado para uma origem, você só precisa enviar o cabeçalho uma vez. Os cabeçalhos NEL e Report-To serão aplicados a solicitações futuras para a mesma origem e continuarão coletando erros de acordo com o valor max_age usado para configurar o coletor.

O valor do cabeçalho precisa ser um objeto JSON que contenha um campo max_age e report_to. Use o último para referenciar o nome do grupo do coletor de erros de rede:

GET /index.html HTTP/1.1
NEL: {"report_to": "network-errors", "max_age": 2592000}

Sub-recursos

Exemplo: se example.com carregar foobar.com/cat.gif e esse recurso não for carregado:

  • O coletor NEL de foobar.com é notificado.
  • O coletor NEL de example.com não é notificado.

A regra geral é que o NEL reproduz registros do lado do servidor, gerados no cliente.

Como example.com não tem visibilidade nos registros do servidor de foobar.com, ele também não tem visibilidade nos relatórios do NEL.

Como depurar configurações de relatório

Se os relatórios não aparecerem no servidor, acesse chrome://net-export/. Essa página é útil para verificar se as configurações estão corretas e se os relatórios estão sendo enviados corretamente.

E o ReportingObserver?

ReportingObserver é um mecanismo de relatórios relacionado, mas diferente. Ele é baseado em chamadas JavaScript. Não é adequado para o registro de erros de rede, já que os erros de rede não podem ser interceptados pelo JavaScript.

Servidor de exemplo

Confira abaixo um exemplo de servidor Node que usa o Express. Ele mostra como configurar relatórios de erros de rede e cria um gerenciador dedicado para capturar o resultado.

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}`);
});

Leitura adicional