概要
Webフロントのパフォーマンス診断 - Carpe Diem
で指摘されたブラウザキャッシュの対応をするため調べてみました。
大きく分けて強いキャッシュと弱いキャッシュの2種類のキャッシュがあります。
強いキャッシュ
ブラウザ側でリソースを保持し、期限が切れるまでサーバにHTTPリクエストを発行しません。
なので一度ブラウザにキャッシュされるとサーバ側からハンドリングすることができなくなります。
これを設定する方法は
- Cache-Controlヘッダー
- Expiresヘッダー
の2つがあります。
Cache-Control: max-age
サーバからのレスポンスで以下のようにCache-Control
ヘッダーを付けます。
Cache-Control: max-age=3600
このヘッダーが付いたリソースはブラウザ上では強いキャッシュとして残ります。
max-age
は秒数なので、この場合は1時間ブラウザでキャッシュすることになります。
これが効いている場合Chromeでは以下のように表示されます。
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
を返してキャッシュファイルを再利用します。
ETag
ETag
ヘッダーでは、リソースを一意に識別する値を使用します。
サーバからのレスポンスで以下のようにヘッダーを付けます。
ETag: "fdf93a92572b8d71604a798e70e8f7f3"
そして再リクエストする際は、ブラウザが自動で
If-None-Match: "fdf93a92572b8d71604a798e70e8f7f3"
というリクエストヘッダーをつけます。サーバ側はリソースが更新されていれば新しいリソースを返します。
更新されてなければ304
を返してキャッシュファイルを再利用します。
どちらを使うべきか
両方あればETagが優先されるので、ETagの方のみ設定すれば良いです。
強いキャッシュと弱いキャッシュの使い分け
以下のように使い分けると良いと思います。
キャッシュの種類 | 向いているリソース |
---|---|
強いキャッシュ | 更新があまりないimageなどの静的なアセット |
弱いキャッシュ | 更新が起きやすいHTMLやJSファイル、 サービス側で更新タイミングをハンドリングしたいファイル |
弱いキャッシュでもリクエストが送られなくなる
Chromeなどブラウザによっては弱いキャッシュでもキャッシュした期間が短ければ、リクエストを送らずキャッシュを再利用することもあります。
キャッシュサーバとの関連性
Cache-Control
やExpires
はブラウザだけでなく、キャッシュサーバのキャッシュの判断にも利用されます。
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 |
となります。
まとめ
ブラウザキャッシュには強いキャッシュと弱いキャッシュがあり、用途に応じて使い分ける必要がある、ということでした。