ETag があっても Cache-Control がなければブラウザキャッシュが効いて更新されないことも

2019/06/13   # 
このエントリーをはてなブックマークに追加

このページがわかりやすかった。
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 になっているケース。
83-1
サーバーにリクエストすらせずに自身のキャッシュを使っている。
なので、たとえサーバー側でコンテンツが変わっていて ETag 値も変化したとしても、キャッシュの古いコンテンツが使い続けられる。

いろいろと試行錯誤した結果、コンテンツのレスポンスに、
Cache-Control: must-revalidate, max-age = 0
をつけておけば、毎回サーバーに確認しにいくような動作を Chrome がした。