錯誤碼與重試
每個廠商可呼叫的端點都共用同一套錯誤形狀和重試契約。ProviderClient 對它發出的每一個呼叫,都已經實作了下表「SDK 行為」那一欄——本頁是完整參考,適合在你除錯一個被丟出的錯誤、要實作 SDK 沒覆蓋的呼叫,或想圍繞 isRetryableStatus 寫自己的重試邏輯時查閱。
狀態碼參考
| 狀態碼 | 意義 | 響應體 | SDK 行為 |
|---|---|---|---|
200 且 status: "DECLINED" | BET 的正常業務結果(餘額不足、超出下注限額) | JSON TransactionResponse | 正常返回——不是錯誤,不會重試 |
400 | 請求主體無效(校驗失敗),或請求與其引用的 session 不符(playerRef/gameId/currency 不一致) | JSON { "error": "..." } | 以 PlatformApiError 丟擲,不重試 |
400(nonce) | X-Nonce 缺失或過長 | JSON { "error": "invalid nonce" } | 以 PlatformApiError 丟擲,不重試 |
401(簽名) | 簽名錯誤、缺失,或時間戳過期 | 純文字:invalid signature | 以 PlatformApiError 丟擲,不重試 |
401(重放) | 一個已經被使用過的 nonce | JSON { "error": "replayed request" } | 以 PlatformApiError 丟擲,不重試 |
401(身份) | 未能解析出廠商身份,或 session token 無效/已過期 | JSON { "error": "..." } | 以 PlatformApiError 丟擲,不重試 |
403 | 該 session 屬於和本次請求簽名者不同的廠商 | JSON { "error": "..." } | 以 PlatformApiError 丟擲,不重試 |
404 | 沒有匹配的路由——檢查 baseUrl 和路徑 | JSON { "error": "..." } | 以 PlatformApiError 丟擲,不重試 |
409 | 同一個 transactionId 已有請求在處理中 | JSON { "error": "..." } | 帶退避重試,複用同一個 transactionId |
429 | 超出限流(按租戶) | JSON { "error": "rate limit exceeded" },附 Retry-After 響應頭(秒數) | 以 PlatformApiError 丟擲,不會自動重試——請自行遵循 retryAfter |
500 | 平台側可重試的失敗(包含判定為 TIMED_OUT 的情況) | JSON { "error": "..." } | 帶退避重試 |
503 | 遊戲或運營商轉接器未配置 | JSON { "error": "..." } | 帶退避重試——見下方提示 |
除了上面純文字的 401 之外,其他每一種錯誤響應都共用 { "error": "<訊息>" } 這個結構。
503 會被重試,儘管它通常不是暫時性問題
isRetryableStatus 把任何 >= 500 的狀態碼都視為值得重試,包括 503。實務上,這個介面回傳 503 幾乎都代表平台這一側的遊戲/運營商配置有問題(某個轉接器還沒接好),而不是一時的抖動——所以如果 submitTransaction 呼叫在連續多次 503 後耗盡所有重試次數,這是提示你去檢查接入配置,而不是懷疑網路問題。
PlatformApiError
對上面每一個不可重試的響應(400/401/403/404/429),以及重試耗盡後的 409/5xx丟擲:
class PlatformApiError extends Error {
status: number
body: string // 原始響應體
requestId?: string // 對應平台的 X-Request-Id 響應頭
retryAfter?: string // 若存在,對應 Retry-After 響應頭
hint?: string // 一句話指出最可能的原因
}requestId 是交給平台支援最有用的單一資訊——讓對方能直接在伺服端日誌裡找到這個確切的請求,而不需要你描述時間點或請求內容。hint 是針對該狀態碼最可能原因的一句話提示,並非窮盡診斷。範例見除錯。
RequestTimeoutError
當單次請求嘗試超過 timeoutMs(預設 15000)時丟擲。這是網路層級的失敗,不是 PlatformApiError——因為根本沒有收到任何 HTTP 響應——所以會像其他網路錯誤一樣被重試。只有當所有嘗試(含全部重試)都逾時後,呼叫方才會收到這個錯誤。
class RequestTimeoutError extends Error {
timeoutMs: number
hint: string
}isRetryableStatus
function isRetryableStatus(status: number): boolean
// 409 和任何 >= 500 為 true
// 其他一律為 false,包括 429匯出給需要圍繞 SDK 沒覆蓋的呼叫自建重試邏輯的呼叫方使用。這正是 ProviderClient 內部使用的判斷邏輯——網路錯誤(DNS 失敗、連線被拒等)永遠視為可重試,與這個函式無關,因為它根本沒有產生一個可供檢查的 HTTP 狀態碼。
冪等性與重試
重試永遠複用同一個 transactionId(針對錢包呼叫)——這是平台用來分辨「同一次邏輯嘗試的重試」和「一次全新嘗試」的方式。透過 ProviderClient 發出的呼叫完全不需要你自己實現這套邏輯;如果你是手動簽名發送請求,也要用同樣的方式在自己的重試中複用同一個 ID。
免費旋轉回呼(由平台呼叫、且平台不會重試)用的是不同的冪等鍵——requestRef/externalRef,因為需要重試的一方換成了平台,而它並不會這麼做。完整契約見免費旋轉回呼。