Carpe Diem

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

ブラウザのキャッシュ

概要

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

強いキャッシュと弱いキャッシュ

強いキャッシュはブラウザ側でリソースを有効期間まで保持し、再利用します。GETリクエスト自体投げません。
弱いキャッシュはブラウザ側が「このファイル持ってるけど更新されてる?」といったリクエストを投げ、更新されていればリソースを返し、更新されていなければ304を返してリソースはキャッシュのものを再利用します。

強いキャッシュ

ブラウザ側でリソースを保持し、期限までサーバにGETリクエストを発行しません。Chromeでは以下のように表示されます。

f:id:quoll00:20170623145730p:plain

これを設定する方法は

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

の2つがあります。


Expires

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

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

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


Cache-Control: max-age

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

Cache-Control: max-age=3600

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


どちらを使うべきか

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

弱いキャッシュ

キャッシュした時の日付やハッシュ値をサーバに送り、更新されているかどうかチェックします。更新されていなければキャッシュのリソースを再利用します。

これを設定する方法は

  • 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の方のみ設定すれば良いです。

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

更新があまりない静的なアセットに関しては強いキャッシュを、更新が頻繁にあり、ブラウザ側でリクエストを送られないと適切な表示ができなくなるものに関しては弱いキャッシュを使ったり、キャッシュさせない方針が良いと思います。

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

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

webmasters.stackexchange.com

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

Cache-ControlExpiresはキャッシュサーバのキャッシュの判断にも利用されます。

Originのレスポンスヘッダー キャッシュサーバの挙動
Cache-Control: max-ageがある その期間キャッシュを保持
Expiresがある その期間キャッシュを保持
Cache-Control: no-cache キャッシュを保持しない

しかしながらCDNによってはその仕様に則らないものもありますので、利用する時は注意してください。
先日のメルカリの障害はCDNがこのRFCに則っていないため起きたものと考えられます。

tech.mercari.com

まとめ

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

ソース