条件付きリクエストとETag活用
同時更新の衝突を避けたり、無駄な転送を減らしたりするのに役立つのが条件付きリクエストです。RFC 9110の挙動を踏まえて、APIで使いやすい形に整理しました。
主要ヘッダー
目的ごとにヘッダーが分かれています。ETagは強いタグ("abc")と弱いタグ(W/"abc")の2種類があります。
条件付きヘッダー一覧
| ヘッダー | 用途 | 応答の例 |
|---|---|---|
| If-None-Match | 弱い比較でタグを照合。* は対象URIに現在の表現があるかを調べる。 | 一致時はGET/HEAD: 304、その他: 412 |
| If-Modified-Since | GET/HEADの日時による再検証。If-None-Matchがある場合は無視する。 | 指定日時以降に変更なし: 304 |
| If-Match | 強い比較で一致したときだけ処理。更新競合の検出に使う。 | 条件不成立: 原則412 |
| If-Unmodified-Since | 指定日時以降に変更されていないことを要求。If-Matchがある場合は無視する。 | 指定日時より新しい: 原則412 |
| If-Range | Rangeを伴うGETで利用。不一致ならRangeを無視して通常の全体取得へ。弱いETagは指定できない。 | GET (Range): 206 or 200 |
よくある使い方
転送量削減と衝突回避の2軸で覚えると実務で迷いません。
パターン別フロー
- キャッシュ確認: 保存したETagをGET/HEADのIf-None-Matchに付けます。弱い比較で一致したら304となり、保存済みの表現を使えます。
- 新規作成の衝突回避: 作成先URIへのPUTにIf-None-Match: * を付け、現在の表現があれば412で拒否します。判定対象は要求先URIです。コレクションへのPOSTで新規要素の重複を防ぐ仕組みとは異なります。
- 更新の楽観ロック: GETで得た強いETagをIf-Matchに付けてPUT/PATCHします。412なら最新内容を再取得して差分を確認し、上書きしてよいか判断します。条件照合と更新はサーバー側で一体として処理します。
- 削除の衝突回避: DELETEのIf-Matchが不成立なら原則412で、削除を実行しません。認証失敗や404など通常の検査が先に返る場合もあります。冪等性のために毎回204を返す必要はありません。
- 帯域節約の部分取得: Range + If-Rangeで中断したダウンロードを再開。タグ不一致なら通常の200で全体を返す。
返すステータスの目安
認証・権限など通常の要求検査を通った後に条件を評価します。条件によって「一致」と「条件成立」の意味が違うことに注意しましょう。
コード対応
| 状況 | 返すコード | メモ |
|---|---|---|
| GET/HEADでタグ一致、または指定日時以降に変更なし | 304 Not Modified | 本文なし。必要なヘッダーは下記を参照。Last-Modifiedが常に必須という意味ではない。 |
| 条件不一致(更新のIf-Match/If-Unmodified-Since) | 412 Precondition Failed | 再取得を促す。 |
| 条件ヘッダー必須なのに無い | 428 Precondition Required | RFC 6585 §3。必要な条件の指定方法を説明する。428応答はキャッシュ保存不可。 |
設計メモ
ETagは実装方法でぶれやすいので、発行ポリシーをチームで共有しておくと安全です。
運用のコツ
- 強いETagは表現データが変われば変える必要があります。単なる更新番号を使う場合も、言語版や圧縮形式など異なる表現に同じ強いタグを流用しないようにします。
- If-None-Matchは弱い比較、If-Matchは強い比較です。W/"abc"はIf-Matchでは"abc"と一致しません。If-Rangeに日時を使うのは、ETagがなく、その日時を強い検証子として使える場合に限ります。
- 評価順はIf-Match(なければIf-Unmodified-Since)、次にIf-None-Match(なければGET/HEADのIf-Modified-Since)、最後にGETのIf-Rangeです。If-Matchが通ってもIf-None-Matchの評価は省略しません(RFC 9110 §13.2.2)。
- 304では、同じ要求への200で送るはずのContent-Location・Date・ETag・Vary・Cache-Control・Expiresを送ります。本文やトレーラーは付けません(RFC 9110 §15.4.5)。
- If-MatchやIf-Unmodified-Sinceが不成立でも、同じ状態変更が既に成功したと判断できる場合は2xxを返せる例外があります。単にエラーを隠すために成功扱いにはしません。
まとめ
304は保存した内容の再利用、412は条件不成立を示します。保存と再検証の違い、ステータスコードの選び方も合わせて確認しましょう。