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.js と public/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 ドキュメントに対するものかどうかを確認することです。

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 のキャッシュ ヘッダーを構成する

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

前のステップで使用した setHeaders function を基に、追加のロジックを追加して、特定のリクエストがバージョン管理された URL に対するものかどうかを確認し、そうであれば Cache-Control: max-age=31536000 ヘッダーを追加できます。

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

これらの一般的なルールに一致する正規表現は、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 のネットワーク パネルを構成する。

ここで注目すべき列は、Name、Status、Cache-Control、ETag、Last-Modified です。

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

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

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

最初の行は、移動先の HTML ドキュメント用です。これは Cache-Control: no-cache で適切に処理されます。そのリクエストの HTTP レスポンス ステータスは 304 です。つまり、ブラウザはキャッシュに保存された HTML をすぐに使用せず、Last-Modified と ETag の情報を使用してウェブサーバーに HTTP リクエストを送信し、キャッシュに保存されている HTML に更新があるかどうかを確認しました。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 のネットワーク パネルで、想定されるキャッシュ動作が使用されていることを確認するために必要な手順も確認しました。