概要
Webフロントのパフォーマンス診断 - Carpe Diem
で指摘されたブラウザキャッシュの対応をするため調べてみました。
強いキャッシュと弱いキャッシュ
強いキャッシュはブラウザ側でリソースを有効期間まで保持し、再利用します。GETリクエスト自体投げません。
弱いキャッシュはブラウザ側が「このファイル持ってるけど更新されてる?」といったリクエストを投げ、更新されていればリソースを返し、更新されていなければ304
を返してリソースはキャッシュのものを再利用します。
強いキャッシュ
ブラウザ側でリソースを保持し、期限までサーバにGETリクエストを発行しません。Chromeでは以下のように表示されます。
これを設定する方法は
- 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
を返してキャッシュファイルを再利用します。
ETag
ETag
ヘッダーでは、リソースを一意に識別する値を使用します。
ETag: "fdf93a92572b8d71604a798e70e8f7f3"
というヘッダーが返ります。
そして再リクエストする際はブラウザが自動で
If-None-Match: "fdf93a92572b8d71604a798e70e8f7f3"
というリクエストヘッダーをつけ、サーバ側でリソースが更新されていれば新しいリソースを返します。
更新されてなければ304
を返してキャッシュファイルを再利用します。
どちらを使うべきか
両方あればETagが優先されるので、ETagの方のみ設定すれば良いです。
強いキャッシュと弱いキャッシュの使い分け
更新があまりない静的なアセットに関しては強いキャッシュを、更新が頻繁にあり、ブラウザ側でリクエストを送られないと適切な表示ができなくなるものに関しては弱いキャッシュを使ったり、キャッシュさせない方針が良いと思います。
弱いキャッシュでもリクエストが送られなくなる
Chromeなどブラウザによっては弱いキャッシュでもキャッシュした期間が短ければ、リクエストを送らずキャッシュを再利用することもあります。
キャッシュサーバとの関連性
Cache-Control
やExpires
はキャッシュサーバのキャッシュの判断にも利用されます。
Originのレスポンスヘッダー | キャッシュサーバの挙動 |
---|---|
Cache-Control: max-ageがある | その期間キャッシュを保持 |
Expiresがある | その期間キャッシュを保持 |
Cache-Control: no-cache | キャッシュを保持しない |
しかしながらCDNによってはその仕様に則らないものもありますので、利用する時は注意してください。
先日のメルカリの障害はCDNがこのRFCに則っていないため起きたものと考えられます。
まとめ
ブラウザキャッシュには強いキャッシュと弱いキャッシュがあり、用途に応じて使い分ける必要がある、ということでした。