整合
設計可靠的付款回調
回調可能延遲送達、重複送達或次序錯亂。本文提供實用指引,說明如何建立一個在這些情況下仍保持正確的端點:真確性檢查、快速確認、冪等處理及對帳。
· 7 分鐘閱讀
為何需要回調
卡付款並非總會在客戶眼前完成。身份驗證可能需時,發卡機構可能回應緩慢,客戶亦可能在被重新導向返回前已關閉分頁。然而,付款最終仍會到達一個最終狀態。回調(有時稱為 webhook)就是支付平台告知閣下伺服器該狀態的方式。
在彩虹匯的 API 中,閣下在建立付款時提供一個回調網址。當付款狀態改變時,例如變為處理中、已批准或已拒絕,平台會向該網址發送一個 POST 請求。若閣下的伺服器沒有以 HTTP 200 回應,平台會重新發送回調。
重試機制令回調變得可靠,但同時亦令處理方式過於簡單的回調處理程式變得不可靠。一個假設每則訊息只會按次序送達一次、且只會來自平台的處理程式,終有一天會出錯。本文其餘部分說明如何避免這種情況。
將每個回調視為不可信的輸入
閣下的回調網址可從互聯網存取。任何得知該網址的人,都可以發送一個看似付款已獲批准的請求。在根據回調採取行動之前,請先確認其真確性。
- 核實真確性:使用 API 文件所述的機制進行核實,並拒絕任何未能通過檢查的請求。比對簽名時應使用恆定時間比較。
- 確認該筆付款屬於閣下。在閣下自己的記錄中查找付款令牌或訂單編號。對於並非由閣下建立的付款,應忽略其回調。
- 核對金額及貨幣是否與訂單相符,然後才履行訂單。
- 使用 HTTPS 作為回調網址,並確保端點不含任何會在錯誤訊息中洩露內部數據的邏輯。
迅速確認,分開處理
平台正在等待閣下的回應。如果閣下的處理程式先發送電郵、更新存貨、呼叫其他服務,然後才作出回應,一個緩慢的依賴服務便可能令回應超出發送方的逾時限制。此時即使閣下的工作可能已經成功,回調仍會被重新發送。
較穩健的做法是將處理程式一分為二。接收端點負責核實請求、將其持久記錄(例如寫入數據庫表或佇列),然後回應 HTTP 200。另一個獨立的工作程序其後處理已儲存的回調。若處理失敗,工作程序會按自己的時間表重試,平台無須重新發送任何內容。
只有在閣下未能記錄回調時(例如因為數據庫無法使用),才應回應非 200 的狀態碼。這正是閣下希望平台再次嘗試的情況。
確保處理過程冪等
由於回調會被重新發送,閣下的處理程式有時會多次收到同一則通知。處理過程必須是冪等的:同一則訊息處理兩次,效果必須與處理一次相同。
- 以付款令牌及所報告的狀態作為處理的鍵值,並記錄已處理過的組合。
- 將狀態變更及其附帶效果(例如將訂單標示為已付款)包含在單一數據庫交易之內,或使用唯一性約束,使第二次嘗試無法產生第二次效果。
- 對於會離開閣下系統的附帶效果,例如送貨請求或客戶電郵,應以閣下自身記錄中的狀態變更為觸發條件,而非以訊息的送達為觸發條件。
同一原則亦適用於相反方向。當閣下的伺服器建立付款或退款,而網絡錯誤令回應無法收到時,盲目重試可能會產生重複操作。再次發送前,請先透過 API 查核該操作的狀態。
處理次序錯亂的訊息
網絡延遲及重試意味着「處理中」的通知可能在「已批准」的通知之後才送達。如果閣下的處理程式只是照單寫入收到的任何狀態,訂單便可能由已付款倒退回處理中。
應將付款狀態建模為具有允許轉換的狀態機。最終狀態(例如已批准或已拒絕)不應被較早的非最終狀態覆寫。當回調報告的轉換不為閣下的模型所容許時,請勿套用;應記錄下來,如有需要,再透過 API 查核當前狀態。
退款及爭議會在付款獲批准後帶來更多狀態轉換。請在同一模型中預先規劃,而非日後再臨時附加。
以 API 進行對帳
回調告訴閣下某些事情已經改變;API 則告訴閣下當前狀態為何。兩者應同時使用。
- 在進行高價值或不可逆轉的操作(例如放行貨品)之前,以付款令牌查詢該筆付款並確認其狀態。
- 設定一項排程工作,找出在閣下記錄中停留於處理中狀態超出預期時間的付款,並查詢其狀態。這可以找出閣下端點在服務中斷期間遺漏的回調。
- 定期將閣下的記錄與結算報告進行對帳,使財務及工程團隊採用相同的數字。
對帳令回調由單一故障點變為兩個獨立訊號之一。任何一方遺失時,另一方都能補上。
測試失敗情況
使用測試環境演練在正常流量中甚少出現的路徑:重複送達的回調、逾時的處理程式、被拒絕後再次嘗試的付款,以及屬於未知付款的回調。回調格式的詳情載於 API 文件 (opens in a new tab),而回調整合指南則概述了相關步驟。