代表的な面接トピック

一般的な面接:HTTP 428 Precondition Requiredはどのようにロストアップデートを防ぐのか?

一般普通
Offer.cc 編集チーム公開日 更新日

質問

あるAPIは、If-MatchのないPUTに対して428を返し、ETagが古い場合には412を返します。その違い、クライアントフロー、およびサーバーがロストアップデートを防ぐ仕組みを説明してください。

プロンプトとコンテキスト

2つのクライアントが同じドキュメントを編集しています。サーバーは条件付き更新を要求します。条件がない場合は428を返し、提供された条件が一致しなくなった場合は412を返します。後の書き込みが前の書き込みを通知なしに上書きしないように、ETag、If-Match、キャッシュ、およびリトライがどのように連携するかを説明してください。

面接官が評価するポイント

  • ポリシー要件としての428と、評価された条件の不一致としての412の区別。
  • 楽観的並行性制御のための強いETagとIf-Matchの使用。
  • 読み取り、編集、送信、競合表示、およびマージステップの設計。
  • キャッシュ、冪等性、監査性、およびリトライ境界の処理。

回答前に明確にすべき質問

  1. どのリソースと書き込みメソッドが条件を必要とし、If-Match: *は許可されていますか?
  2. ETagは強いETagか弱いETagのどちらですか?また、保護対象のリプレゼンテーションが更新されるたびに変更されますか?
  3. クライアントは428、412、404、409をそれぞれどのように処理すべきですか?
  4. 競合はフィールド単位でマージされますか?ユーザーが選択しますか?それとも破棄されますか?
  5. キャッシュ、バージョン、冪等性キー、および監査の要件は何ですか?

30秒の回答フレームワーク

クライアントはリソースをGETしてそのETagを保存し、その後If-Matchを付けて編集内容を送信します。条件がない場合は428が返され、クライアントに条件を追加するよう指示します。不一致の場合は412が返され、リソースが変更されたことを伝えます。クライアントは無作為に上書きする代わりに、再読み込みし、差分を表示し、マージして新しいETagで送信します。サーバーは強いETagをアトミックに比較し、バージョンと監査データを記録し、条件付きキャッシュを書き込み保護から分離して保持します。

ステップごとの詳細解説

ステップ 1: 428と412の分離

428はサーバーのポリシー応答です。リクエストに必要な前提条件が含まれていませんでした。412は、指定された条件が評価され、現在のリソース状態がそれを満たさなかったことを意味します。どちらも、元のリクエストを変更せずにリトライすることを意味するものではありません。

ステップ 2: リソースバージョンの生成

サーバーは強いETagを発行し、保護対象のリプレゼンテーションが変更されるたびにそれを変更します。クライアントは、ローカルのタイムスタンプのみに依存するのではなく、GETからのそのETagを編集のベースラインとして保存します。

ステップ 3: If-Matchの送信

クライアントは、PUT、PATCH、またはその他の副作用を伴う更新とともにIf-Matchを送信します。書き込みを適用する前に、サーバーは現在のETagをアトミックに比較します。一致した場合のみ処理が進み、不一致の場合は412を返してリソースを変更しないままにします。

http
GET /documents/42
ETag: "v17"

PUT /documents/42
If-Match: "v17"

ステップ 4: 競合の解決

412の後、再度GETを実行し、ローカルの変更の横にサーバーバージョンを表示します。ポリシーで許可されている場合はフィールドをマージし、それ以外の場合はユーザーに選択を求めます。古いIf-Match値を再送信してはいけません。

ステップ 5: キャッシュ動作の設計

条件付きGETはIf-None-Matchを使用して304を受け取ることができますが、書き込み保護はIf-Matchを使用します。キャッシュは古いETagを最新として扱ったり、リソースの状態を明らかにするような方法でエラーをキャッシュしたりしてはなりません。

ステップ 6: 障害とリトライの処理

ネットワークタイムアウト後、非冪等な書き込みを盲目的に再実行しないでください。リソースバージョンを問い合わせるか、冪等性キーを使用して結果を確認します。428には前提条件が必要です。412には再読み込みとマージが必要です。

ステップ 7: 記録と検証

バージョン、ETag、競合数、自動マージ率、およびユーザーの破棄を追跡します。並行更新テストでは、一方のライターが成功し、もう一方が412を受け取り、すべてのバージョン変更に対して監査証跡が存在することを示す必要があります。

高品質な回答サンプル

GETから"v17"のような強いETagを返し、編集フェーズ中にクライアントがそれを保持するようにします。If-MatchのないPUTは、条件付き更新を使用する指示とともに428を返します。古いETagはアトミック比較に失敗し、412を返します。その後、クライアントは最新バージョンをGETし、差分を表示し、マージして、古い条件を再送するのではなく新しいETagでリトライします。If-None-Matchと304は読み取りを最適化しますが、書き込みは保護しません。タイムアウトした書き込みは、再実行前にバージョンまたは冪等性キーでチェックされ、競合率とマージ率を監視します。

よくある間違い

  • 428と412の両方を一時的なエラーとして扱い、無限にリトライすること。
  • 強いETagの比較をクライアントのタイムスタンプに置き換えること。
  • 412を受信した後にサーバーバージョンを上書きすること。
  • If-None-Matchのキャッシュ検証とIf-Matchの書き込み保護を混同すること。
  • タイムアウト後に、副作用を伴う書き込みを無条件に再実行すること。

フォローアップ質問と回答

フォローアップ 1: なぜLast-Modifiedを使用しないのですか?

タイムスタンプの精度やクロックの問題により、2つのバージョンが同一に見えることがあります。強いETagはリプレゼンテーションのバージョンに直接バインドされるため、ロストアップデートを防ぐのにより適しています。

フォローアップ 2: If-Match: *はどのような場合に役立ちますか?

APIコントラクトに応じて、リソースが存在しなければならないことを示したり、不明なバージョンに対する作成や置換を防いだりします。無条件の書き込みではありません。

フォローアップ 3: 412は409とどのように異なりますか?

412はHTTPの前提条件が満たされなかったことを意味します。409は、ビジネスレベルでリクエストが現在のリソース状態と競合していることを意味します。APIは両方を使用する場合がありますが、リカバリアクションを明記する必要があります。

フォローアップ 4: フィールドレベルでどのようにマージしますか?

共通のベースライン、サーバーバージョン、およびローカルバージョンをロードし、フィールドポリシーに従ってマージします。同じフィールドの競合をユーザーに送信し、その結果を新しいETagとともに送信します。

フォローアップ 5: キャッシュが古いETagを返した場合はどうなりますか?

編集前に適切なキャッシュ制御または再検証を使用し、更新が失敗した後はオリジンからの読み取りを強制します。現在のバージョンとのサーバーのアトミックな比較は信頼できる基準であり続けます。

フォローアップ 6: 並行性の安全性をどのようにテストしますか?

2つのクライアントに1つのETagを読み取らせ、同時に書き込みを行わせます。正確に1つが成功し、もう一方が412を受け取ることを確認し、その後リトライ、タイムアウト、キャッシュ、および監査パスを検証します。

公開情報ソース

関連する質問