題幹與適用場景
這道題考察後端工程師能否把並發控制落實到 HTTP 協定邊界。重點是區分快取驗證與寫入保護,說明服務端如何比較實體標籤、返回明確狀態,以及資料庫更新和回應標頭如何保持一致。
面試官考察什麼
- 是否理解 ETag、If-Match、If-None-Match 的不同語意。
- 是否能用強驗證器保護寫入,避免舊版本覆蓋新資料。
- 是否能定義 412、428、409 等衝突與前置條件失敗的邊界。
- 是否能說明代理快取、重試、權限與跨副本一致性風險。
回答前需要釐清的問題
先確認資源是整體替換還是部分更新,客戶端是否必須帶版本,是否允許離線編輯與合併,ETag 是否代表完整表示或業務版本,以及讀寫是否經過快取、負載平衡與多個資料庫副本。
30 秒回答框架
讀取資源時返回表示對應的 ETag。修改請求必須帶 If-Match,服務端在同一交易中比較目前版本並執行帶版本條件的更新;不匹配返回 412,不帶前置條件則按策略返回 428。成功後生成新 ETag。GET 使用 If-None-Match 可返回 304,但快取驗證不能取代寫入保護。
分步驟深入解答
1. 區分快取驗證與寫入保護
If-None-Match 適合 GET 快取驗證:表示未變更時返回 304。If-Match 用於要求目前表示匹配,常見於 PUT、PATCH 或 DELETE。不要把「客戶端快取命中」當成「客戶端有權覆蓋目前資源」,兩者的比較方向與失敗結果不同。
2. 選擇可安全比較的 ETag
寫入保護使用強 ETag,確保位元組表示或定義的版本完全匹配;弱 ETag 適合語意等價的快取場景,不應用來允許精確更新。ETag 不應洩露內部遞增 ID 或敏感資訊,可以由正規化表示、版本號與不可預測鹽計算,並在權限過濾後生成。
3. 把比較與更新放在同一邊界
服務端讀取目前版本、比較 If-Match 與更新資源必須在同一資料庫條件寫入中完成,例如 UPDATE ... WHERE id = ? AND version = ?。受影響列數為零時返回 412;成功後遞增版本並用新版本生成 ETag。不要先在應用內查詢,再發起沒有條件的寫入。
4. 設計失敗回應與重試路徑
缺少必要前置條件可返回 428,ETag 不匹配返回 412,業務狀態衝突可返回 409。回應應包含目前資源或重新讀取的提示,但不要替客戶端靜默覆蓋。客戶端收到 412 後重新 GET、展示差異或執行明確的欄位合併,再帶新的 ETag 重試;自動重試必須有次數與冪等邊界。
5. 處理快取、複製與維運細節
生成 ETag 的讀取必須來自能看到最新寫入的版本,或接受有界的讀後寫延遲。代理快取要正確轉發 ETag、If-Match 與 If-None-Match,敏感資源使用合適的快取控制。記錄請求 ID、舊新版本、結果與衝突率,便於定位客戶端長期使用舊表示或某個副本落後。
高品質示範回答
我會讓 GET 返回資源表示和強 ETag,例如由正規化內容與版本生成。PUT、PATCH、DELETE 必須帶 If-Match;服務端在資料庫中執行帶版本條件的更新,受影響列數為零就返回 412,缺少前置條件按介面策略返回 428,成功則遞增版本並返回新的 ETag。GET 帶 If-None-Match 且標籤匹配時返回 304,這只是快取節省,不能取代寫入保護。客戶端收到 412 後重新讀取、展示差異或執行明確欄位合併,再帶新標籤重試。跨副本讀取要保證看到最新版本,代理必須正確轉發條件標頭;透過衝突率、舊版本請求與副本延遲監控協定是否被正確使用。
常見錯誤
- 只用客戶端時間戳比較,忽略時鐘偏差與表示差異。
- 用弱 ETag 保護精確寫入,導致語意相近但內容不同的更新被接受。
- 先查詢版本,再無條件更新,讓比較與寫入之間存在競態。
- 把 412、409、428 混為一個通用錯誤,客戶端無法決定下一步。
- 讓服務端自動覆蓋衝突,丟失使用者剛剛讀取後的修改。
- 只在應用節點生成標籤,卻沒有考慮快取與資料庫副本的可見性。
追問與應對
ETag 可以直接用資料庫自增版本嗎?
可以把版本作為內部生成輸入,但對外應按 HTTP 語意編碼並避免暴露敏感業務資訊。若表示會因欄位篩選或權限不同而變化,標籤必須在對應表示邊界生成。
PATCH 的兩個欄位互不衝突,可以自動合併嗎?
可以提供明確的欄位級合併協定,但仍應校驗客戶端基於哪個 ETag。合併規則、不可合併欄位與稽核記錄必須公開,不能把「欄位不同」當成所有業務衝突都可忽略。
為什麼不只返回 409?
412 表示 If-Match 等前置條件失敗,428 表示要求客戶端先提供前置條件,409 更適合資源目前狀態與業務操作衝突。區分它們能讓客戶端選擇重新讀取、補充標頭或調整業務動作。
經過 CDN 時如何避免舊標籤寫入?
寫請求應到達權威源,快取只服務讀取;回應和請求條件標頭按規範轉發。更新成功後使相關快取失效或縮短可接受的陳舊窗口,並監控源站版本與邊緣標籤差異。