このページがわかりやすかった。
HTTPヘッダチューニング Etag・Last-Modified | REDBOX Labo
Last-Modified と If-Modified-Since
ETag と If-None-Match によるキャッシュ制御
- 前回リクエストした際にサーバーから ETag を受信している場合は、ETag の内容を
If-None-Match
ヘッダに含めてサーバーに送信 - サーバーが
If-None-Match
を受信したら、サーバー内にあるコンテンツと比較 - 同じ ETag の場合はブラウザに
304(Not Modified)
を返す - ブラウザはサーバーから 304 を受信したら自分自身のキャッシュを読み込んでブラウザに表示する
ETag 値の生成(S3の場合)
S3 の場合、CORS の設定で ExposeHeader に指定しておけばよいみたい。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>0</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
S3 から直接配信する場合は考慮しなくていいけど、
先のページの「ETAGに潜む罠」に書いてあるように、
同一コンテンツが複数マシンに散らばっている場合は Etag 値の生成方法を考慮しないと、逆効果になってしまうので注意。
ETag があっても Cache-Control がないと
ETag によるキャッシュ制御を行っているとしても、併せて Cache-Control
を指定しないと、
そもそもコンテンツが変化していないかサーバーに確認しにこないことがある のでハマった。
Chrome の場合、以下のように Size が from memory cache
とか from disk cache
になっているケース。
サーバーにリクエストすらせずに自身のキャッシュを使っている。
なので、たとえサーバー側でコンテンツが変わっていて ETag 値も変化したとしても、キャッシュの古いコンテンツが使い続けられる。
いろいろと試行錯誤した結果、コンテンツのレスポンスに、
Cache-Control: must-revalidate, max-age = 0
をつけておけば、毎回サーバーに確認しにいくような動作を Chrome がした。