通用面試:HTTP 428 Precondition Required 如何避免遺失更新?
題干與適用場景
兩個用戶端同時編輯同一份文件。伺服器要求更新請求攜帶條件標頭:缺少條件時回傳 428,條件存在但不再匹配時回傳 412。請說明 ETag、If-Match、快取與重試如何配合,避免後寫入覆蓋先寫入。
面試官考察點
- 是否理解 428 是「必須帶條件」的策略要求,412 是條件已評估但失敗。
- 能否用強 ETag 與 If-Match 建立樂觀並發控制。
- 能否設計讀取、編輯、提交、衝突展示與重新合併流程。
- 能否處理快取、冪等性、稽核與異常重試邊界。
回答前需要釐清的問題
- 哪些資源與寫入方法必須條件化,是否允許
If-Match: *? - ETag 是強驗證器還是弱驗證器,是否隨每次表示變化?
- 用戶端遇到 428、412、404 或 409 時分別怎麼處理?
- 衝突需要欄位級合併、人工選擇還是直接放棄?
- 是否有快取、版本號、冪等鍵與稽核要求?
30 秒回答框架
用戶端先 GET 資源並保存 ETag,編輯後用 If-Match 提交。缺少條件時伺服器回傳 428,表示用戶端必須補上條件;條件不匹配時回傳 412,表示資源已被修改。用戶端應重新讀取、展示差異並合併後再提交,不能盲目覆蓋。伺服器用強 ETag 原子比較並記錄版本與稽核,快取必須正確處理條件請求。
分步驟深入解答
第一步:區分 428 與 412
428 來自伺服器策略:請求沒有所需前置條件;412 表示請求帶了條件,但目前資源狀態不滿足。兩者都不是讓用戶端直接重試原請求的訊號。
第二步:產生資源版本
伺服器為表示產生強 ETag,內容或受保護的版本變化時更新它。GET 回應返回 ETag,用戶端把它保存為編輯基線,而不是只保存本地時間戳。
第三步:提交 If-Match
用戶端在 PUT、PATCH 或其他有副作用的更新中傳送 If-Match。伺服器在套用寫入前原子比較目前 ETag;匹配才執行,否則回傳 412 並保持資源不變。
GET /documents/42
ETag: "v17"
PUT /documents/42
If-Match: "v17"第四步:處理衝突
收到 412 後重新 GET,向使用者展示伺服器版本與本地改動差異。欄位可安全合併時產生新版本;無法自動合併時要求使用者選擇,不能把舊的 If-Match 再發一次。
第五步:設計快取行為
條件 GET 可以用 If-None-Match 取得 304,但寫入保護使用 If-Match。快取層不能把舊 ETag 當成目前版本,也不能快取會洩露資源狀態的錯誤回應。
第六步:處理異常與重試
網路逾時後不要直接重放非冪等寫入;先查詢資源版本或使用冪等鍵確認結果。428 需要補條件,412 需要重新讀取與合併,重試邏輯必須區分這兩類動作。
第七步:記錄與驗證
記錄版本、ETag、衝突次數、自動合併率與人工放棄率。用並發更新測試驗證「先到者成功、後到者 412」,並確認稽核記錄能還原每次版本變化。
高品質示範回答
我會讓 GET 返回強 ETag,例如 "v17",用戶端編輯時保留它。PUT 沒有 If-Match 就回傳 428,明確提示必須使用條件更新;帶有舊 ETag 則在原子比較失敗時回傳 412。用戶端收到 412 後重新 GET,展示伺服器與本地差異,合併後用新 ETag 再提交,絕不重複傳送舊條件。快取以 If-None-Match/304 優化讀取,不能取代寫入保護。逾時的寫請求先查詢版本或用冪等鍵確認結果,並監控衝突率與自動合併率。
常見錯誤
- 把 428 和 412 都當成服務暫時不可用並無限重試。
- 使用用戶端時間戳代替強 ETag 的原子比較。
- 收到 412 後直接覆蓋伺服器版本。
- 混淆 If-None-Match 的快取驗證與 If-Match 的寫入保護。
- 逾時後無條件重放有副作用的寫請求。
追問及應對
追問一:為什麼不用 Last-Modified?
時間戳精度與時鐘問題可能讓兩個版本看起來相同;強 ETag 直接綁定表示版本,更適合防止遺失更新。
追問二:If-Match: * 什麼時候有用?
它表達「資源必須存在」或避免在未知版本上建立/覆蓋,具體語義要由 API 文件規定;不能把它當成無條件寫入。
追問三:412 與 409 有什麼區別?
412 是 HTTP 條件標頭未滿足;409 表示請求與目前資源狀態發生業務衝突。介面可以同時使用,但回應應說明可恢復動作。
追問四:如何做欄位級合併?
讀取共同基線、伺服器版本與本地版本,按欄位策略合併;對同一欄位的衝突交給使用者,並用新 ETag 重新提交。
追問五:快取返回舊 ETag 怎麼辦?
編輯前的 GET 使用適當快取控制或 revalidation,提交失敗時強制讀取源站;伺服器仍以目前版本原子比較為準。
追問六:怎樣測試並發安全?
讓兩個用戶端讀取同一 ETag 並同時寫入,驗證只有一個成功、另一個收到 412;再覆蓋重試、逾時、快取與稽核鏈路。