先釐清哪個環節沒有回覆
畫面逾時,只表示瀏覽器沒有收到可用回覆,不能據此判定伺服器沒有建立訂單。要求可能根本未到達,亦可能已獲接納但回覆在途中遺失;訂單服務完成時,付款或存貨服務也可能仍在處理。這些狀態須分開記錄。若「重試」只是重新提交同一購物籃,便可能產生兩張訂單、兩次留貨指令或兩項員工工作。顧客見到錯誤而再按一次是合理行為,因此介面與伺服器都要處理這種不確定性。先界定要保護的業務動作:顧客一次有意的提交,只建立一張訂單。
AWS 對冪等 API 的說明是:同一要求用同一識別碼重複送達,其效果應與送達一次相同。這是設計目標,並非所有 HTTP 要求天生具備的特性。每按一次就產生新識別碼,保護便會失效;把新一宗購買沿用舊碼,又會錯誤地合併兩個意圖。顧客進入最後提交步驟時,可建立穩定的提交識別碼;網絡重試、重新整理頁面或短暫斷線時沿用。只有顧客明確展開另一宗購買,才用新碼。這是技術參照,不能代替顧客看得懂的訂單編號。
把按鈕暫時停用可減少連按,卻不能證明只建立了一張訂單。顧客可能開另一分頁,瀏覽器可能重送要求,背景工作也可能把同一訊息送達兩次。最終判斷應放在負責建立訂單的伺服器邊界:把提交識別碼連同結果保存,設唯一性規則,並讓同時到達的要求取得同一結果。首次處理仍在進行時,回覆清晰的「處理中」狀態及查詢途徑;在同一識別碼尚未查到已確認訂單前,不應宣稱成功。客服亦可按提交參照查找紀錄,而非單靠顧客的截圖猜測。
把訂單與後續動作逐一分開
訂單建立後,可能觸發付款、留貨、確認電郵及執貨指示。即使建立訂單的要求已有防重機制,後續每項動作也不會自動安全。應為每項有後果的動作設定穩定參照,連結訂單及動作類型。例如付款嘗試須對應相關訂單及支付供應商的要求識別碼;留貨則應對應訂單明細與留貨事件。背景工作重送失敗訊息時,接收端先查核該項效果是否已記錄。這是按 AWS 冪等指引推導出的實務設計,並非對任何結帳供應商行為的保證。
Stripe 的 API 文件說明為何不能不查版本便照搬設計。其 API v1 會保存使用同一識別碼首次開始執行要求的回應,包括某些伺服器錯誤,並可在識別碼至少保留二十四小時後清除;重試時亦會比較參數。API v2 對失敗或部分失敗工作的重試方式另有描述。因此,收到已保存的錯誤,不代表可斷言付款沒有發生;供應商暫存的識別碼亦不是永久的公司防重紀錄。須查閱實際使用版本的文件,保存供應商要求參照,並把其結果與自家訂單狀態核對,然後才指示員工收款、退款或改用另一付款途徑。
須決定哪些紀錄必須一同提交,哪些動作可事後核對。訂單紀錄與提交識別碼應在同一交易中寫入。對外部支付供應商的呼叫通常不能與本地資料庫交易合併,所以要保留明確付款狀態、記錄發出的要求,並把回調或查詢結果互相關聯。訊息重送時,存貨也不可悄悄扣減兩次。若訂單已建立而後續動作失敗,應顯示「待付款」或「待配貨」等狀態,而非另建新訂單。列明由哪個團隊處理未決狀態、以甚麼證據核實,比籠統聲稱不同系統之間絕不重複處理更實際。
以回覆遺失為例演練
假設一家香港小型零售商的顧客確認購買兩盞檯燈,瀏覽器以提交參照 A 發出要求。伺服器把參照 A 與訂單 105 一同寫入,但連線在訂單編號返回前中斷。畫面應說明結果未明,提供查詢狀態的途徑,並在重試時沿用 A。顧客再按一次,伺服器發現 A 已對應訂單 105,便回覆該訂單現時狀態,而不建立訂單 106。若付款仍未確認,頁面應直說「待確認」。這些編號只供測試情境說明,並非真實商戶數據或成效預測。
再改變一項條件:顧客在重試前更改數量。相同識別碼配上不同內容,不應暗中改寫第一張訂單。Stripe v1 對參數不一致的重試作比較,是一個具體例子。自家訂單服務可顯示原訂單,要求顧客清楚展開新購買;若業務規則容許,也可提供明確的原訂單修改流程。反過來說,兩個購物籃內容相同,也不一定是同一購買意圖,顧客可能真的想買兩次。識別碼綁定特定提交嘗試,訂單編號則記錄其結果;單憑購物籃相似程度判斷,並不可靠。
測試不應只限於快速連按兩次。要模擬資料庫提交後回覆遺失、相同識別碼同時送達、工作佇列重送、付款回覆遲到,以及處理中查詢狀態。每種情況均檢查訂單數量、付款參照、存貨變動及員工工作。預期結果並非所有畫面立刻顯示成功,而是公司能識別同一次提交,避免非預期的額外效果,並如實告知顧客狀態。驗收前應保存測試環境的實際紀錄;按鈕的單元測試通過,並不能證明付款和出貨邊界已有保護。
讓客服與顧客有可用的處理方法
介面至少要分辨三種訊息:訂單已確認、結果仍在核查、確定沒有建立訂單而須重新提交。結果未明時,不宜只顯示籠統的「失敗」。顧客應有安全的查詢方法,例如已登入帳戶或適當的私人參照,並避免顯示其他顧客資料。客服建議再次付款前,先核對提交參照、訂單編號及付款參照。若本地已有訂單,但供應商結果尚未對妥,員工須有書面處理路線。即使調查需時,也可讓顧客知道公司正在處理甚麼。
自家的防重紀錄應按合理的業務重試及核對期限訂定保存時間,不應假設支付供應商暫存識別碼的時限足以涵蓋公司的訂單歷史。約定誰可人手解除卡住的訂單,以及要附上甚麼證據。顧客確實要求第二次購買時,要清楚記錄新意圖並產生新提交參照。事後再檢視真實事故:哪個回覆遺失、哪項效果重複、畫面有否誤導。負責人可先抽一宗逾時結帳,從瀏覽器要求追到付款和存貨紀錄,再請開發者示範沿用同一參照重試時會返回同一訂單。
進行前先確認
- 回覆遺失後沿用同一提交參照,能否找回原訂單?
- 付款及留貨各自重試時,會否造成重複效果?
- 要求顧客再付款前,員工能否先核對未明結果?


