リソースごとに方針を割り当てる(サーバー単位ではない)
ヘッダーを変更する前に代表的なURLのインベントリを作成してください:ホーム、コンテンツページ、アプリケーションシェル、CSS、JavaScript、画像、フォント、API、ログイン、アカウント、チェックアウト、ダウンロードなど。各URLについて、レスポンスが公開か個人化か、バイトが変わるとURLが変わるか、修正がどれだけ迅速に訪問者に届くべきかを記録します。
そのインベントリから方針マトリクスを作成します。公開のコンテンツアドレス化されたアセットは、安定したアドレスのHTMLとは異なるルールが必要です。Cache-Controlがないレスポンスであってもヒューリスティックにキャッシュされることがあるため、明示的なルールの方がテストしやすいです。
保存された応答が再利用できる期間。max-ageで秒単位に指定します。
Cache-Control用語を正確に使う
Cache-Controlはブラウザや共有キャッシュに対してレスポンスの保管と再利用方法を伝えます。max-age=Nはfreshな間は再利用を許可します。s-maxage=Nは共有キャッシュのfreshnessを設定してそこではmax-ageをオーバーライドします(ブラウザはs-maxageを無視します)。publicは任意のキャッシュを許可し、privateはブラウザキャッシュを許可するが共有キャッシュでの保管を防ぎます。
no-cacheは保存を許容しますが再利用前にオリジンでの検証を要求します。no-storeはキャッシュに保存してはならないことを意味しますが、完全なプライバシー制御ではありません。must-revalidateは期限切れ後に古いコンテンツを出すことが許容されない場合に使用します;この指定があるとオリジンが利用不可のときにキャッシュは504を返すことがあり、古いフォールバックを返すことを防げます。
no-store は保存を取り除くだけで単にチェックを要求するわけではありません。保存してはならない本当に機密なレスポンスに限定して使ってください。
イミュータブル(不変)アセットは長い寿命を付与する前にバージョン化する
バージョン付きアセットURLはコンテンツフィンガープリントやリリースバージョンを含みます(例:app.4f2c.js)。アセットのバイトが変わったら別のURLを公開し、HTMLの参照を更新します。キャッシュから見ると新しいリソースになるため、無効化がすべてのブラウザに届かなくても訪問者は新しいアセットを取得します。
表現がそのFreshness lifetimeの間に変わらないと分かる場合、Cache-Control: max-age=31536000, immutable のようなパターンが実用的です。immutableは対応するクライアントに対してfreshな間の条件付き再検証を行わないよう指示します。同じURLで変更されうる可変ファイルに対して年単位のmax-ageやimmutableを適用してはいけません。キャッシュされたHTMLがそれらを参照し続ける可能性がある間は、以前のフィンガープリント済みアセットを保持してください。
HTMLがアセットURLを選ぶため、リリースの順序付けは参照される世代を保持する必要があります。
HTMLは長期キャッシュにするのではなく検証で新鮮にする
HTMLは通常、人間が見る安定したURLを持ち、コンテンツ、アセット参照、機能フラグ、セキュリティ通知で変わります。保守的な公開HTMLパターンは Cache-Control: no-cache と ETag と Last-Modified を組み合わせることです(プラットフォームが正しく生成できる場合)。ブラウザはボディを保存しますが再利用前に条件付きリクエストを行い、未変更ならば 304 Not Modified をボディなしで受け取ります。
ETagはリソースのバージョンを識別します。古くなった応答ではブラウザはそれを If-None-Match に入れて送信できます;一致すればサーバは 304 を返し、一致しなければ新しい表現を返します。RFCは可能であれば200レスポンスにETagとLast-Modifiedの両方を付与することを推奨しています。no-cacheはBackやForwardのナビゲーションで必ず検証を行うことを保証するものではありません(ブラウザがセッション履歴のスナップショットを復元することがあるため)。
ETagは表現が変わったときに必ず変わらなければなりません;オリジンやデプロイを跨いでテストしてください。
公開配信と個人化・機密レスポンスを分離する
CDNのような共有キャッシュは1つのレスポンスを複数ユーザーで再利用する可能性があります。アカウント固有のHTMLやAPIデータを誤ってユーザー間で再利用させないでください。ブラウザに残り得る個人化コンテンツについては、private, no-cache が出発点として合理的です:共有保管を防ぎ、検証を要求します。Set-Cookie ヘッダーだけではキャッシュを止められません。
保存してはならないレスポンスについては no-store を使い、アプリケーションコード、CDNルール、Service Worker、ブラウザストレージ、ログ、エラーページを確認してください。ヘッダーだけでプライバシー、コンプライアンス、決済セキュリティ要件が満たされるわけではありません。機密フローについては資格あるセキュリティ、プライバシー、決済のレビュワーに評価してもらってください。
サインイン、サインアウト、アカウント切替、権限変更をウォームなブラウザとCDNキャッシュでテストしてください。
キャッシュ変更は取り消し可能なリリースとして展開する
未キャッシュおよび再訪リクエストのベースラインヘッダーとボディの挙動をキャプチャしてください。ステージングでは、まずバージョン化アセットをデプロイし、その後それらを参照するHTMLをデプロイし、古いキャッシュされたHTMLが新しいオリジンに対してどう振る舞うかをテストします。オリジン直結パスとCDN経路の両方がある場合は両方を確認してください。DevToolsのNetworkパネルで意図した方針と再訪挙動が表示されるはずです。
リリースマニフェストにアセットURL、ヘッダールール、設定バージョンを記録してください。もしリリースが互換性のないクライアントファイルを組み合わせてしまった場合は、互換性のあるHTMLとアプリケーション挙動に戻しますが、公開済みのフィンガープリント済みファイルを上書きしないでください。既知の良い世代にHTMLを向け直し、キャッシュされたHTMLがそれらを要求する間は両方の世代を保持します。共有キャッシュのパージはすべてのブラウザに新鮮なレスポンスの破棄を強制できません。
ヘッテストの失敗、アセット404、バージョン不一致を次のリリースチェックリストへの修正項目に変えてください。
