If-None-Match: "abc" は「ETag が “abc” と一致しないなら本文をくれ」というお願い。
つまりここでの条件は「サーバーが本文を送るための条件」で、成否で返すものが変わる。
| サーバー側の ETag | 条件 | レスポンス |
|---|---|---|
"def"(変わっていた) | 一致しない → 成立 | 200 + 本文 |
"abc"(変わっていない) | 一致した → 不成立 | 304(本文なし) |
304 は「条件が成立しなかったので 200 の代わりに返す返事」。 だから条件付きリクエストを送っていないのに 304 が返ることはない。
1回目: GET /style.css
→ 200 OK ETag: "abc" Cache-Control: max-age=600
max-age 経過 → キャッシュは stale になるが破棄はされない
2回目: GET /style.css If-None-Match: "abc"
→ 304 ETag: "abc" …本文なし・鮮度だけ更新
or 200 ETag: "def" …本文あり・差し替え
腹落ちポイントは キャッシュの期限切れ ≠ 再ダウンロード。
期限が切れたのは「確認せずに使ってよい期間」だけで、実体は手元に残っている(stale 状態)。
条件付きリクエストはそれを捨てずに「まだ使える?」と問い合わせだけする手段で、304 はその答え。
304 は Cache-Control を再送するのでキャッシュは fresh に戻る。
逆にバリデーターが無いレスポンスは確認手段がないので期限切れ = 再ダウンロード確定。つまり ETag を付けることは「キャッシュの寿命を延長する権利」を与えることに近い。