1. 題目與使用情境
一個訂單 API 接收 JSON 請求。用戶可能送出語法正確但欄位關係不合法的資料,也可能依據舊版本更新訂單,或嘗試建立已存在的使用者名稱。請定義 409 與 422 的使用界線,讓客戶端知道應修改請求、重新讀取資源,還是停止重試。
2. 面試官考察重點
- 能否區分「請求內容無法依語意處理」與「請求和資源目前狀態衝突」。
- 是否知道 422 的相同請求通常會得到相同結果,不應靠盲目重試解決。
- 能否把並行控制、冪等重試與錯誤回應契約連起來。
- 能否說明 400、412 等相鄰狀態碼的界線,並維持團隊一致的約定。
3. 回答前需要釐清的問題
- API 是否使用 ETag、版本號或其他樂觀並行控制?
- 「名稱已存在」是請求欄位規則,還是目標集合目前狀態造成的衝突?
- 客戶端能否重新讀取資源並呈現差異?
- 團隊是否已有統一的錯誤碼、欄位路徑與重試策略?
4. 30 秒回答框架
先看失敗原因屬於哪一個面向:如果伺服器理解媒體類型與語法,但請求中的業務語意無法處理,回傳 422;如果請求本身可理解,卻和目標資源目前狀態衝突,回傳 409。400 用於無法解析的請求,412 更適合條件請求的前置條件失敗。最後補充機器可讀錯誤碼、修復建議與並行版本資訊。
5. 分步深入解答
第一步:定義 422 的界線
422 表示內容類型已理解、語法正確,但其中的指令無法處理。例如日期區間結束早於開始、列舉值不允許,或欄位組合違反業務約束。這類錯誤通常與資源此刻由誰修改無關;客戶端應修改 payload 後再送出。
第二步:定義 409 的界線
409 表示請求和目標資源目前狀態衝突。典型情境是版本號過期、訂單已出貨卻再次取消,或建立操作和現有唯一資源衝突。回應應盡量帶上目前版本、衝突類型與客戶端可採取的下一步。
第三步:處理相鄰狀態碼
JSON 結構損壞、缺少必要語法元素時用 400。帶有 If-Match 的請求未滿足條件時可用 412;這比把所有條件失敗都籠統歸為 409 更精確。具體選擇仍應寫入公開 API 契約,避免各端點各自解釋。
第四步:設計重試與錯誤內容
422 不應自動重試相同 payload,因為不修改請求通常會再次失敗。409 是否能重試取決於衝突類型:客戶端可以重新讀取資源、合併變更後重試,但不能在未知狀態下無限循環。錯誤內容應包含穩定的 code、欄位路徑或資源識別、目前版本與修復建議,不記錄憑證等敏感資訊。
6. 高品質示範回答
我會先判斷失敗是 payload 語意問題,還是資源狀態競爭。日期範圍反轉、無效列舉和欄位組合不成立屬於 422;伺服器能理解請求,但訂單已出貨、版本號過期或唯一資源已存在,屬於 409。JSON 無法解析用 400,帶 If-Match 的條件不滿足可用 412。
>
對 422,我回傳穩定業務錯誤碼和欄位路徑,客戶端修改資料後再送。對 409,我回傳衝突類型、伺服器版本或目前狀態,客戶端先讀取,再決定合併、放棄或重新執行。客戶端不應對兩者都無條件重試;冪等鍵只能避免重複執行,不能消除並行衝突。所有端點沿用同一份狀態碼與錯誤內容契約,並監控各類錯誤的修復率。
7. 常見錯誤
- 把所有業務驗證失敗都回傳 409,讓客戶端誤以為重新讀取資源即可解決。
- 把版本衝突回傳 422,失去「目前狀態已改變」的訊號。
- 對 422 或 409 做無上限自動重試,造成請求風暴。
- 只回傳人類可讀 message,沒有穩定錯誤碼、欄位路徑和修復方向。
- 看到「重複」就固定使用一個狀態碼,卻沒有定義它是 payload 規則還是資源狀態衝突。
8. 追問及應對
追問一:重複使用者名稱應該是 409 還是 422?
如果 API 把使用者名稱唯一性視為目前集合狀態,409 能表達資源狀態衝突;如果團隊把它定義為欄位語意驗證,也可以統一使用 422。重點是契約穩定,客戶端行為可預測。
追問二:409 一定可以重試嗎?
不一定。版本衝突可能在合併後重試,已出貨訂單的取消衝突則應停止並顯示目前狀態。回應需要告訴客戶端衝突是否可修復,而非暗示所有 409 都安全重試。
追問三:422 能用於權限不足嗎?
不應用它取代驗證授權語意。未驗證通常是 401,已驗證但無權限通常是 403;422 應保留給內容語意無法處理的情況。