ブラウザキャッシュの仕組み
はじめに
最近Denoをよく触っており、DenoのSSRフレームワークであるFreshのミドルウェア・キャッシュについて調べている際にブラウザキャッシュのEtagヘッダが使用されており、気になったのでブラウザキャッシュの仕組みについて調べてみました。
Etagの正体
Etagとは、ブラウザキャッシュの仕組みの中で使用されるHTTPレスポンスヘッダーでリソースの特定のバージョンに関する識別子のことです。
Etagがあることでウェブサーバーは、コンテンツが変更されていない場合はレスポンス全体を再送する必要がないので、キャッシュがより効率的になる。
ブラウザキャッシュの設定について
ブラウザキャッシュを設定する際に必要なHTTPレスポンスヘッダーはEtagを含めて以下の通りです。
-
Expires
ヘッダー -
Cache-Control
ヘッダー -
Last-Modified
ヘッダー -
Etag
ヘッダー
それぞれのHTTPヘッダーについて
Expiresヘッダー
Expiresヘッダーは、一度リソースを取得したら、Expiresに設定されている期限までは自動でブラウザ内部にキャッシュされます。
このキャッシュが消えるには、1. そもそもキャッシュされたファイル自体が消えるまたは、2. キャッシュの期限が切れる場合のみ。→強いキャッシュ。
Expiresヘッダーのキャッシュが一度有効になると、HTTPリクエストを送らなくなります。(期限内)
またクライアントとサーバで日付のずれが発生すると意図した通りに動かなくなるので注意です。
Cache-Controlヘッダー
このCache-Controlヘッダーは上記のExpiresヘッダーが抱えていた「サーバとクライアントのずれ」の問題を解消した強いキャッシュです。
max-age
パラメーターでキャッシュの期限を秒数で指定することで、強制的にその期限内で一度有効になるとHTTPリクエストを送らなくなります。
下記の場合は一時間キャッシュを有効にします。
Cache-Control : max-age=3600
Last-Modifiedヘッダー
上記の二つのヘッダーとは異なり、このLast-ModifiedヘッダーはHTTPリクエストを送信しなくなることはありません。
このヘッダーが有効になると条件付きのGETリクエストを送信します。それによりレスポンスを小さくすることが可能です。
条件付きGETリクエストとは、クライアントが送信するHTTPリクエスト内に含まれている条件に合致すれば、HTTPサーバーは 304 Not Modified
レスポンスを返します。
※304 Not Modified
レスポンスとは、ブラウザに対して「キャッシュを使用するように」と指示するためのstatus codeです。
Last-Modifiedヘッダーの挙動は下記のようになります。
- 初回のリソースの取得の際にサーバはレスポンスヘッダーに Last-Modified ヘッダー を付与します。
- 次に同じURLのリソースを取得するとき、ブラウザはHTTPリクエストヘッダーに
If-Modified-Since
ヘッダーを付与します。このレスポンスヘッダーが含まれたGETリクエストは、条件付きGETリクエストと呼ばれます。 - サーバーは、受信したリクエストの
If-Modified-Since
ヘッダーの値を確認して、そのURLのリソースの最終更新日がこのIf-Modified-Since
ヘッダーに指定した日時よりもあとだった場合には通常のHTTPレスポンスを返し、そうではない場合には304 Not Modified
レスポンスを返します。 -
304 Not Modified
レスポンスを返すことでブラウザは、リソースの取得をキャッシュから行います。
Etagヘッダー
EtagヘッダーはLast-Modifiedヘッダーと同様に条件付きGETリクエストを送信することでキャッシュを実現します。
Etagヘッダーの挙動は以下のようになります。
- 初回のリソースの取得の際にHTTPサーバはEtagヘッダーに一意のハッシュを付与します。
- ブラウザはその受け取ったレスポンスのリソースファイルと、Etagハッシュをブラウザキャッシュに保存します。
- 次に同じリソースにアクセスする際に、ブラウザはリクエストヘッダーに
If-None-Match
に先ほどブラウザキャッシュに保存したEtagの値をセットしてリクエストを送信します。 - サーバで受け取った
If-None-Match
のハッシュと初回アクセス時にセットしたEtagハッシュが一致した場合は、リソースの更新がないとみなし、304 Not Modified
ステータスをresponse bodyなしで返送し、キャッシュされたレスポンスのバージョンがまだ使用可能 (新しい) であることをクライアントに通知します。
補足
Last-ModifiedヘッダーとEtagヘッダーが混在した場合は、Last-Modifiedヘッダーは無視されEtagヘッダーが優先されます。
参考情報
Discussion