HTTP キャッシュ動作の構成

この Codelab では、Express サービス フレームワークを実行する Node.js ベースのウェブサーバーから返される HTTP キャッシュ保存ヘッダーを変更する方法について説明します。また、Chrome の DevTools の [ネットワーク] パネルを使用して、期待どおりのキャッシュ保存動作が実際に適用されていることを確認する方法も示します。

サンプル プロジェクトを理解する

サンプル プロジェクトで使用する主なファイルは次のとおりです。

  • server.js には、ウェブアプリのコンテンツを提供する Node.js コードが含まれています。Express を使用して HTTP リクエストとレスポンスを処理します。特に、express.static() は公開ディレクトリ内のすべてのローカル ファイルを配信するために使用されるため、serve-staticドキュメントが役立ちます。
  • public/index.html はウェブアプリの HTML です。ほとんどの HTML ファイルと同様に、URL の一部としてバージョン情報が含まれていません。
  • public/app.15261a07.jspublic/style.391484cf.css は、ウェブアプリの JavaScript アセットと CSS アセットです。これらのファイルの URL には、それぞれ内容に対応するハッシュが含まれています。index.html は、読み込む特定のバージョン付き URL を追跡する役割を担います。

HTML のキャッシュ ヘッダーを構成する

バージョン情報を含まない URL のリクエストに応答する場合は、必ず Cache-Control: no-cache をレスポンス メッセージに追加してください。また、Last-Modified または ETag のいずれかの追加レスポンス ヘッダーを設定することをおすすめします。index.html はこのカテゴリに分類されます。この手順は 2 つに分けることができます。

まず、Last-Modified ヘッダーと ETag ヘッダーは、etag 構成オプションと lastModified 構成オプションによって制御されます。これらのオプションはどちらも、すべての HTTP レスポンスでデフォルトで true に設定されるため、現在の設定では、この動作を取得するためにオプトインする必要はありません。ただし、構成で明示的に指定することはできます。

次に、Cache-Control: no-cache ヘッダーを追加できる必要がありますが、HTML ドキュメント(この場合は index.html)のみが対象となります。このヘッダーを条件付きで設定する最も簡単な方法は、カスタム setHeaders function を作成し、その中で受信リクエストが HTML ドキュメント用かどうかを確認することです。

  • [Remix to Edit] をクリックして、プロジェクトを編集可能にします。

server.js の静的サービング構成は、最初は次のようになっています。

app.use(express.static('public'));
  • 上記の変更を行うと、次のようになります。
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    }
  },
}));

バージョン付き URL のキャッシュ ヘッダーを構成する

fingerprint」またはバージョン情報を含み、コンテンツが変更されることがない URL のリクエストに応答する場合は、レスポンスに Cache-Control: max-age=31536000 を追加します。app.15261a07.jsstyle.391484cf.css はこのカテゴリに分類されます。

前の手順で使用した setHeaders function を基に、特定のリクエストがバージョン付き URL のものかどうかを確認し、バージョン付き URL の場合は Cache-Control: max-age=31536000 ヘッダーを追加するロジックを追加できます。

最も堅牢な方法は、正規表現を使用して、リクエストされたアセットが、ハッシュが該当する特定のパターンと一致するかどうかを確認することです。このサンプル プロジェクトの場合、常に 0 ~ 9 の数字と a ~ f の小文字のセットから 8 文字(つまり、16 進数文字)です。ハッシュは常に両側が . 文字で区切られています。

これらの一般的なルールに一致する正規表現は、new RegExp('\\.[0-9a-f]{8}\\.') と表現できます。

  • setHeaders 関数を次のように変更します。
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    const hashRegExp = new RegExp('\\.[0-9a-f]{8}\\.');

    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    } else if (hashRegExp.test(path)) {
      // If the RegExp matched, then we have a versioned URL.
      res.setHeader('Cache-Control', 'max-age=31536000');
    }
  },
}));

DevTools を使用して新しい動作を確認する

静的ファイル サーバーの変更が完了したら、DevTools の [ネットワーク] パネルを開いてライブアプリをプレビューし、正しいヘッダーが設定されていることを確認します。

  • [ネットワーク] パネルに表示される列をカスタマイズして、最も関連性の高い情報を含めるには、列見出しを右クリックします。

DevTools の [Network] パネルを構成する。

ここで、注意すべき列は NameStatusCache-ControlETagLast-Modified です。

  • DevTools を開いて [ネットワーク] パネルを表示した状態で、ページを更新します。

ページが読み込まれると、[ネットワーク] パネルに次のようなエントリが表示されます。

ネットワーク パネルの列。

最初の行は、移動先の HTML ドキュメント用です。これは Cache-Control: no-cache で適切に提供されます。そのリクエストの HTTP レスポンス ステータスは 304 です。つまり、ブラウザはキャッシュに保存された HTML をすぐに使用しないことを認識し、代わりに Last-ModifiedETag の情報を使用して、キャッシュに保存されている HTML に更新があるかどうかを確認するために、ウェブサーバーに HTTP リクエストを送信しました。HTTP 304 レスポンスは、更新された HTML がないことを示します。

次の 2 行は、バージョン管理された JavaScript アセットと CSS アセット用です。Cache-Control: max-age=31536000 で提供され、各 HTTP ステータスは 200 になります。使用されている構成のため、Node.js サーバーに実際のリクエストは送信されません。エントリをクリックすると、レスポンスが「(ディスク キャッシュから)」であることなど、詳細が表示されます。

ネットワーク レスポンスのステータスが 200。

ETag 列と Last-Modified 列の実際の値はあまり重要ではありません。重要なのは、それらが設定されていることを確認することです。

まとめ

この Codelab の手順を完了すると、HTTP キャッシュを最適に使用するために、Express を使用して Node.js ベースのウェブサーバーで HTTP レスポンス ヘッダーを構成する方法を理解できます。また、Chrome の DevTools の [ネットワーク] パネルで、期待どおりのキャッシュ保存動作が使用されていることを確認する手順も用意されています。