Cache-Control について考える (2) : max-age, s-maxage, 実際のユースケース

投稿日:

前回の続編なので、まずはそちらから参照して欲しい。

Cache-Control: s-maxage=604800, max-age=604800, must-revalidate

今回は max-age と s-maxage を中心にして「オリジンサーバのレスポンスでどうキャッシュ期間を指定すればいいか」を考え、実際のユース ケースを詰めてみる。

キャッシュ期間の制御

基本的には max-ages-maxage の2種類を覚えておけばいい。

max-age

もっとも基本的なキャッシュ期間の制御だ。期限をコンテンツを取得してからの秒数で設定する。例えば max-age=3 とすれば、コンテンツを取得してから3秒間がキャッシュ有効期間だ。

全てのブラウザはこれに従うが、CDNはこれに従うものと従わないものがある。CDNに対しては下に挙げる s-maxage ディレクティブを使う(ブラウザ向けの max-age とCDN向けの s-maxage を両方設定する)のが事故らなくて良いと思う。

なお max-age=0no-cache と同様の「キャッシュを保存するが利用前に確認する」という指示になり、キャッシュを禁止する目的では利用できない。

s-maxage

CDNなどの共有キャッシュ(不特定多数で共有する形態のキャッシュのこと)に対するキャッシュ期間の制御だ。期限をコンテンツを取得してからの秒数で設定する。例えば s-maxage=3 とすれば、コンテンツを取得してから3秒間がCDNでのキャッシュ有効期間だ。

ブラウザは s-maxage には従わず、CDNは s-maxage を優先する。つまり max-ages-maxage を両方指定しておけば、ほぼ確実にブラウザとCDNに対してキャッシュ期間が設定できる。

大半のCDNが s-maxage に対応しているが、Akamaiは対応しない。前回でも数多の例を挙げてきたように、CDNはサービスごとの挙動の違いが大き過ぎる。利用前に絶対に仕様を確認すべきだ。

なお s-max-age ではないので注意。

ユース ケース

シンプルに設定していく。ヘッダを設定する方法そのものは適当にググって欲しい(とりあえずなら .htaccess 置いて Header set を書けばいい)。

私はWebエンジニアではないので、ここに記した例よりも良い方法があると思うが、ひとまず Cache-Control ヘッダを理解する一助にしてほしい。

管理画面

CMSの管理画面などは以下を指定している

Cache-Control: no-store
  • これひとつでCDNもブラウザもキャッシュしなくなる

ページ (htmlコンテンツ)

ページそのものに対しては以下を指定している

Cache-Control: s-maxage=604800, max-age=604800, no-cache
  • CDNには1週間キャッシュさせる (s-maxage=604800
    • コンテンツを更新した場合は、WordPressのプラグインなどで自動的にCDNにキャッシュパージさせる
    • 私は no-cache を無視するCDNを利用している。ここではCDNが no-cache に従う必要はなく、むしろ従ってほしくない。
  • ブラウザには1週間キャッシュさせ、必ずコンテンツの更新を確認してから利用させる (max-age=604800, no-cache)
    • コンテンツに更新がなければ、高速なブラウザキャッシュを表示する
    • もしコンテンツが更新されていた場合は、必ず新しいものが取得される

アセット(js/css/画像)

変化の少ないアセットは以下を指定している

Cache-Control: s-maxage=604800, max-age=86400
  • CDNには1週間キャッシュさせる(s-maxage=604800
    • コンテンツを更新した場合は、WordPressのプラグインなどで自動的にCDNにキャッシュパージさせる
  • ブラウザには1日キャッシュさせる (max-age=86400)
    • 有効期限内は更新の確認すら不要になり、最も高速である。ただしブラウザキャッシュは遠隔でパージする方法がないので扱いが難しい。
    • なにか不具合があっても大抵の人間は1日は待ってくれるという視点から、キャッシュ期間を1日にした。出来ればさらに長くしたい(後述)
    • この場合であっても、 F5でリロードした場合は、ブラウザは条件付きリクエストで新しいコンテンツの有無を確認する。それも抑制したい場合は immutable ディレクティブを利用することができる。

なおアセットについては、 cache-busting というキャッシュのコントロールテクニックがある。正直アセットのキャッシュが1日間では勿体無いので、そちらの手法で max-age に頼らずキャッシュパージを行うのが良いだろう。

このテーマの続きとして補足ページも作成した。