ネットワーク エラー ロギング(NEL)

はじめに

ネットワーク エラー ロギング(NEL)は、オリジンからクライアントサイドのネットワーク エラーを収集するメカニズムです。

NEL HTTP レスポンス ヘッダーを使用して、ネットワーク エラーを収集するようブラウザに指示し、Reporting API と統合してエラーをサーバーに報告します。

以前の Reporting API の概要

以前の Reporting API を使用するには、Report-To HTTP レスポンス ヘッダーを設定する必要があります。その値は、ブラウザがエラーを報告するエンドポイント グループを記述するオブジェクトです。

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 名が指定されていない場合、エンドポイントには「default」という名前が付けられます。
max_age 数値 必須。エンドポイントの存続期間を秒単位で定義する正の整数。値が「0」の場合、エンドポイント グループはユーザー エージェントのレポート キャッシュから削除されます。
endpoints Array<Object> 必須。レポート コレクタの実際の URL を指定する JSON オブジェクトの配列。
include_subdomains ブール値 省略可。現在のオリジンのホストのすべてのサブドメインに対してエンドポイント グループを有効にするブール値。省略した場合、または「true」以外を指定した場合は、サブドメインはエンドポイントに報告されません。

group 名は、文字列をエンドポイントに関連付けるために使用される一意の名前です。Reporting API と統合する他の場所でこの名前を使用して、特定のエンドポイント グループを参照します。

max-age フィールドも必須で、ブラウザがエンドポイントを使用し、エラーを報告する期間を指定します。

endpoints フィールドは、フェイルオーバー機能とロード バランシング機能を提供する配列です。フェイルオーバーとロード バランシングのセクションをご覧ください。グループが endpoints に複数のコレクタをリストしている場合でも、ブラウザは 1 つのエンドポイントのみを選択することに注意してください。複数のサーバーにレポートを一度に送信する場合は、バックエンドでレポートを転送する必要があります。

ブラウザはレポートをどのように送信しますか?

ブラウザは定期的にレポートをバッチ処理し、構成したレポート エンドポイントに送信します。

レポートを送信するために、ブラウザは Content-Type: application/reports+json を含む POST リクエストと、キャプチャされた警告 / エラーの配列を含む本文を発行します。

ブラウザがレポートを送信するタイミング

レポートはアプリから帯域外で配信されます。つまり、レポートがサーバーに送信されるタイミングはブラウザが制御します。

ブラウザは、キューに格納されたレポートを最適なタイミングで配信しようとします。これは、準備が整い次第(デベロッパーにタイムリーなフィードバックを提供するため)行うことができますが、ブラウザが優先度の高い作業を処理している場合や、ユーザーが低速または混雑したネットワークを使用している場合は、配信を遅らせることもできます。ユーザーが頻繁にアクセスするオリジンの場合、ブラウザは特定のオリジンに関するレポートの送信を優先することもあります。

Reporting API を使用する場合、パフォーマンスに関する懸念(アプリとのネットワーク競合など)はほとんどありません。また、ブラウザがキューに格納されたレポートを送信するタイミングを制御する方法もありません。

複数のエンドポイントの構成

1 つのレスポンスで複数の 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"
             }]
           }

または、1 つの 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 に送信します。

フェイルオーバーとロード バランシング

ほとんどの場合、グループごとに 1 つの URL コレクタを構成します。ただし、レポートは大量のトラフィックを生成する可能性があるため、仕様には DNS SRV レコードに触発されたフェイルオーバー機能とロード バランシング機能が含まれています。

ブラウザは、グループ内の最大 1 つのエンドポイントにレポートを配信しようとします。エンドポイントに 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 はオリジンに対してオプトインされるため、ヘッダーを送信する必要があるのは 1 回だけです。NEL と Report-To の両方が、同じ送信元への今後のリクエストに適用され、コレクタの設定に使用された max_age 値に従ってエラーが引き続き収集されます。

ヘッダー値は、max_age フィールドと report_to フィールドを含む JSON オブジェクトにする必要があります。後者を使用して、ネットワーク エラー コレクタのグループ名を参照します。

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

サブリソース

例: example.com が foobar.com/cat.gif を読み込み、そのリソースの読み込みに失敗した場合:

  • foobar.com の NEL コレクタに通知されます
  • example.com の NEL コレクタに通知されない

経験則として、NEL はサーバーサイドのログを再現し、クライアントで生成されます。

example.com は foobar.com のサーバーログを可視化できないため、NEL レポートも可視化できません。

デバッグ レポートの構成

サーバーにレポートが表示されない場合は、chrome://net-export/ にアクセスしてください。このページは、構成が正しく、レポートが適切に送信されていることを確認するのに役立ちます。

ReportingObserver について

ReportingObserver は、関連するものの、異なる報告メカニズムです。JavaScript 呼び出しに基づいています。ネットワーク エラーのロギングには適していません。ネットワーク エラーは JavaScript でインターセプトできないためです。

サーバーの例

以下に、Express を使用する Node サーバーの例を示します。ネットワーク エラーのレポートを構成する方法と、結果をキャプチャする専用ハンドラを作成する方法を示します。

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

関連情報