レスポンスにCache-Control: max-age
がない場合って何も考えずにクライアントにキャッシュされないと思っていたがどうやらそうではないらしい。この挙動自体はRFCでも定義されている。HTTP は可能な限りキャッシュするように設計されているので、Cache-Control が指定されていなくても、条件さえ揃えばキャッシュが可能となっている。これをheuristic cacheと呼ぶらしい。以下の記事でも書いてあるがRFCで計算方法は定義されておらずブラウザごとの実装になるとのこと
Chroniumのソースを見てみる
以下のあたり。max-ageやExpiresがあったらそっちを優先する。最終修正時間に基づくヒューリスティックな値とあるが現在時刻が1月1日0:00でlast-modifiedが1月1日10:00ならその10%は更新されてないと想定してその時間をキャッシュするようになっている。
具体的にはこの辺
if ((response_code_ == net::HTTP_OK || response_code_ == net::HTTP_NON_AUTHORITATIVE_INFORMATION || response_code_ == net::HTTP_PARTIAL_CONTENT) && !must_revalidate) { // TODO(darin): Implement a smarter heuristic. Time last_modified_value; if (GetLastModifiedValue(&last_modified_value)) { // The last-modified value can be a date in the future! if (last_modified_value <= date_value) { lifetimes.freshness = (date_value - last_modified_value) / 10; return lifetimes; } } }
ちょっと気になったのは以下のコメント。stale-while-revalidate
があればstaleになった場合もそっちを優先するらしい。見慣れないので調べてみたらstale-while-revalidate
キャッシュから表示するが裏で非同期にキャッシュを更新しておくためのヘッダーらしい。ヒューリスティックな値がクライアント次第で決まる一方でこのヘッダーを設定しておけばstaleになった際のクライアントの挙動をある程度コントロールすることができそうである。便利そう。とはいえcache-controlをあえてつけないことでブラウザのこれまでの経験則的に設定された計算式から外れたキャッシュを使うくらいなら任せてしまうというのも手なのではないだろうか。
// If the stale-while-revalidate directive is present, then it is used to set // the |staleness| time, unless it overridden by another directive.
感想
Cache-Control?そんなのいらんブラウザに全部お任せじゃ!で済む世界なら楽なんだろうなぁと思った。