301 と 307 リダイレクトでブラウザキャッシュの違いを検証してみた

4 min

HTTP のステータスコードで 301 は恒久的、307 は一時的リダイレクトです。 この 2 つのブラウザキャッシュの挙動を確認してみます。

試してみる

http.server を使った簡易サーバーで、以下の 5 つのエンドポイントを実装しました。

エンドポイントStatusCache-Control
/301301なし(デフォルト)
/301-nocache301no-store
/301-maxage301max-age=10
/307307なし(デフォルト)
/307-cache307max-age=60

すべて /destination へリダイレクトし、サーバーは各リクエストの受信回数をログ出力します。

301 と 307 のデフォルト動作

まず Cache-Control なしで確認しました。

[23:00:41] GET /301         (サーバー受信 #1)   ← 初回のみ届く
[23:00:41] GET /destination (サーバー受信 #1)
[23:00:49] GET /destination (サーバー受信 #2)   ← 2回目以降 /301 は届かない
[23:00:50] GET /destination (サーバー受信 #3)
[23:00:57] GET /307         (サーバー受信 #1)   ← 毎回届く
[23:00:57] GET /destination (サーバー受信 #4)
[23:01:03] GET /307         (サーバー受信 #2)
[23:01:03] GET /destination (サーバー受信 #5)
[23:01:03] GET /307         (サーバー受信 #3)
[23:01:03] GET /destination (サーバー受信 #6)

/301 は初回だけサーバーに届き、2 回目以降はブラウザがキャッシュを使って直接 /destination に遷移しています。 /307 は毎回サーバーに届きます。

この挙動は RFC 9110 § 15.4.2 に定義されており、301 は heuristically cacheable とされています。 307 はデフォルトではキャッシュされません。

Cache-Control でデフォルト動作を上書きできる

キャッシュの可否は Cache-Control ヘッダーで上書きできます。

301 + Cache-Control: no-store

[23:05:41] GET /301-nocache  (サーバー受信 #1)
[23:05:42] GET /301-nocache  (サーバー受信 #2)
[23:05:43] GET /301-nocache  (サーバー受信 #3)

301 なのに毎回サーバーに届いてます。no-store でキャッシュが無効化されていることがわかります。

307 + Cache-Control: max-age=60

[23:05:49] GET /307-cache    (サーバー受信 #1)   ← 初回のみ
[23:05:50] GET /destination  (サーバー受信 #11)  ← 2回目以降は直接
[23:05:50] GET /destination  (サーバー受信 #12)

60 秒間ブラウザがリダイレクト先を記憶しているため、307 ですがキャッシュされています。

Clear-Site-Data: "cache" による削除

誤って 301 でリダイレクトさせてしまった場合、ブラウザはサーバーに問い合わせなくなるため、原則サーバー側から無効化する手段はありません。 ただし Clear-Site-Data: "cache" ヘッダーをレスポンスに付与することで、ブラウザのキャッシュをオリジン単位でクリアさせることができるようです。

[23:27:09] GET /destination  (サーバー受信 #16)  ← /301 はキャッシュ済みで届かない
[23:27:11] GET /clear-cache  (サーバー受信 #3)   ← Clear-Site-Data: "cache" を返す
[23:27:12] GET /301          (サーバー受信 #3)   ← キャッシュが消えて再度届いた
[23:27:12] GET /destination  (サーバー受信 #17)

/clear-cache にアクセスした後、次の /301 リクエストがサーバーに届くようになっています。

まとめ

以下の結果になりました。

Cache-Control なしno-storemax-age=N
301キャッシュされるキャッシュなしN 秒間
307キャッシュなしキャッシュなしN 秒間

キャッシュだから奥が深いのか、奥が深いからキャッシュなのか。 その真相を探るため 我々はアマゾンの奥地へと向かった。おしまい。