Carpe Diem

備忘録。https://github.com/jun06t

ブラウザのキャッシュ

概要

Webフロントのパフォーマンス診断 - Carpe Diem
で指摘されたブラウザキャッシュの対応をするため調べてみました。

大きく分けて強いキャッシュ弱いキャッシュの2種類のキャッシュがあります。

強いキャッシュ

ブラウザ側でリソースを保持し、期限が切れるまでサーバにHTTPリクエストを発行しません
なので一度ブラウザにキャッシュされるとサーバ側からハンドリングすることができなくなります

これを設定する方法は

  • Cache-Controlヘッダー
  • Expiresヘッダー

の2つがあります。


Cache-Control: max-age

サーバからのレスポンスで以下のようにCache-Controlヘッダーを付けます。

Cache-Control: max-age=3600

このヘッダーが付いたリソースはブラウザ上では強いキャッシュとして残ります。
max-ageは秒数なので、この場合は1時間ブラウザでキャッシュすることになります。
これが効いている場合Chromeでは以下のように表示されます。

f:id:quoll00:20170623145730p:plain


Expires

サーバからのレスポンスで以下のようにExpiresヘッダーを付けます。

Expires: Wed, 04 Jul 2012 08: 26: 05 GMT

このヘッダーが付いたリソースはブラウザ上では強いキャッシュとして残ります。
ただしこの日付はブラウザでの時刻と比較をするため、サーバでの時刻とズレが生じる可能性があります。
Chromeでの表示はCache-Controlと同じような感じになります。


どちらを使うべきか

Expiresの方が古くからあるため、ブラウザのサポート範囲としては広いです。
しかしながらモダンブラウザであればCache-Controlには対応しており、両方あればCache-Controlを優先するためCache-Controlのみ付ければ良いです。

弱いキャッシュ

キャッシュした時の日付やハッシュ値をサーバに送り、リソースが更新されているかどうかチェックします。更新されていなければサーバは304を返し、ブラウザはキャッシュのリソースを再利用します。
なので仮にブラウザにキャッシュされても、リソースを更新すればブラウザは新しい方を使ってくれるため、サーバ側でハンドリングできます

これを設定する方法は

  • Last-Modifiedヘッダー
  • ETagヘッダー

の2つがあります。


Last-Modified

Last-Modifiedヘッダーには、そのリソースの最後の変更時間が付けられます。
サーバからのレスポンスで以下のようにヘッダーを付けます。

Last-Modified: Sat, 27 Jun 2015 23:59:59 GMT

そしてこのリソースを再度GETするときは、ブラウザが自動で

If-Modified-Since: Sat, 27 Jun 2015 23:59:59 GMT

というリクエストヘッダーをつけます。サーバ側はリソースが更新されていれば新しいリソースを返します。
更新されてなければ304を返してキャッシュファイルを再利用します。

f:id:quoll00:20170623133323p:plain


ETag

ETagヘッダーでは、リソースを一意に識別する値を使用します。
サーバからのレスポンスで以下のようにヘッダーを付けます。

ETag: "fdf93a92572b8d71604a798e70e8f7f3"

そして再リクエストする際は、ブラウザが自動で

If-None-Match: "fdf93a92572b8d71604a798e70e8f7f3"

というリクエストヘッダーをつけます。サーバ側はリソースが更新されていれば新しいリソースを返します。
更新されてなければ304を返してキャッシュファイルを再利用します。

f:id:quoll00:20170623142825p:plain


どちらを使うべきか

両方あればETagが優先されるので、ETagの方のみ設定すれば良いです。

強いキャッシュと弱いキャッシュの使い分け

以下のように使い分けると良いと思います。

キャッシュの種類 向いているリソース
強いキャッシュ 更新があまりないimageなどの静的なアセット
弱いキャッシュ 更新が起きやすいHTMLやJSファイル、
サービス側で更新タイミングをハンドリングしたいファイル

弱いキャッシュでもリクエストが送られなくなる

Chromeなどブラウザによっては弱いキャッシュでもキャッシュした期間が短ければ、リクエストを送らずキャッシュを再利用することもあります。

webmasters.stackexchange.com

キャッシュサーバとの関連性

Cache-ControlExpiresはブラウザだけでなく、キャッシュサーバのキャッシュの判断にも利用されます。

Originのレスポンスヘッダー キャッシュサーバの挙動
Cache-Control: max-ageがある その期間キャッシュを保持
Expiresがある その期間キャッシュを保持
Cache-Control: no-cache キャッシュがあっても必ずOriginで再検証し、更新されていれば再ダウンロード。更新がなければキャッシュを再利用。弱いキャッシュに近い
Cache-Control: no-store キャッシュを一切保持しない

例えばCloudFrontであれば

Originのレスポンスヘッダー CFの挙動
Cache-Control: max-ageがある Hit from cloudfront
Cache-Control: no-cache 更新がない:RefreshHit from cloudfront
更新がある:Miss from cloudfront
Cache-Control: no-store Miss from cloudfront

となります。

まとめ

ブラウザキャッシュには強いキャッシュと弱いキャッシュがあり、用途に応じて使い分ける必要がある、ということでした。

ソース