Cache-Controlヘッダがないときもブラウザがキャッシュする!?

公開:2021/02/15
更新:2021/02/17
3 min読了の目安(約2800字TECH技術記事 2

はじめに

HTTPのレスポンスヘッダにはCache-Controlヘッダがあります。Cache-Controlヘッダにはレスポンスで得たリソースをどのくらいの期間キャッシュするのか(max-age)やそもそもキャッシュしない(no-store)などの情報を載せることができます。Cache-Controlヘッダを受け取ったブラウザは指定された情報を元にキャッシュをしたりしなかったりします。
ではこのヘッダがない場合はどうなるでしょうか。それが本記事の内容です。

Cache-Controlがない場合

RFC7234では以下のように言及されています。

Since origin servers do not always provide explicit expiration times,
a cache MAY assign a heuristic expiration time when an explicit time
is not specified, employing algorithms that use other header field
values (such as the Last-Modified time) to estimate a plausible
expiration time.

つまり、Cache-Controlヘッダ等で明示的にキャッシュの有効期限が与えられていない場合はheuristic expiration timeでキャッシュする可能性があります。
重要なのはキャッシュする可能性があるというところです。キャッシュしないわけではないのです。(ここ勘違いしていました)

Heuristic Expiration timeとは

これはクライアントが推測・算出したヒューリスティックな有効期限のことを言います。Cache-ControlヘッダやExpiresヘッダによって有効期限が明示的に与えられなかった場合はクライアントはLast-Modifiedヘッダなどの情報から有効期限を算出してキャッシュを行います。(正確に言うと有効期限が明示的に与えられなかった、かつレスポンスコードが200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501の場合に当てはまる)

では具体的にどのように有効期限を算出するのか。実は算出方法はRFCでは定めていません。そのためブラウザの実装によって値は異なる可能性があります。
一般的にはLast-Modifiedヘッダの日時とDateヘッダの日時の差の10%の値を有効期間として定めることが多いとRFC7234に記載されています。
実際にGoogle Chromeはこの算出方法に則っています。
以下Chromiumのソースコードです。

 if ((response_code_ == 200 || response_code_ == 203 ||
       response_code_ == 206) &&
      !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;
      }
    }
  }

https://source.chromium.org/chromium/chromium/src/+/master:net/http/http_response_headers.cc;l=1009

このアルゴリズムによって有効期間を算出すると、リソースの変更がない期間が長くなるほどキャッシュの有効期限も長くなり、より長くリソースがキャッシュされるようになります。

まとめ

Cache-Controlヘッダがない場合はブラウザがHeuristic expiration timeを算出してその有効期限を元にキャッシュしている可能性があります。Cache-Controlヘッダがないからといってキャッシュしないわけではないのです。
ここ挙動を認識していないと意外とハマりがちな部分かなと思います(実際自分もハマりました)。
個人的にはなるべくCache-Controleヘッダ等で明示的にキャッシュ戦略は与えてあげておくと良いのかなと思います。

参考