錯誤與速率限制

錯誤與速率限制

每個端點都以相同的結構回報失敗,並附上機器可讀的錯誤碼與請求 ID。

錯誤回應

呼叫失敗時回傳 success: false。code 是穩定不變、供程式判讀的錯誤碼,error 是供人閱讀的簡短英文訊息,request_id 則用來在我們的日誌中定位這次呼叫。若問題出在輸入,param 會指出有問題的參數。

真實範例

以下是即時回應,在本頁面算繪時從 API 取得。

缺少必填參數 · GET /api/sd/oi · HTTP 400
{
  "success": false,
  "error": "coin required",
  "code": "INVALID_PARAM",
  "request_id": "cb-mwefrxky-2592812a6c"
}
未知的端點 · HTTP 404
{
  "success": false,
  "code": "NOT_FOUND",
  "error": "unknown endpoint: GET /api/this-endpoint-does-not-exist",
  "request_id": "cb-mwefrxl6-9d8e3c8733"
}

錯誤碼

錯誤碼HTTP意義處理方式
INVALID_PARAM400缺少必填參數,或某個值不被接受。已知時,`param` 會指出是哪個參數。請勿原樣重試;請修正請求。
UNAUTHORIZED401已送出 `CB-API-KEY` 標頭,但金鑰未知或已撤銷。公開資料不需要金鑰——請移除該標頭或改用有效的金鑰。請勿原樣重試。
FORBIDDEN403此路由不屬於公開 API(內部或僅限帳戶使用)。請勿重試。
NOT_FOUND404未知的路由,或所請求的幣種/交易所/基金不存在。請勿重試;請對照目錄檢查路徑與識別碼。
RATE_LIMITED429請求數超過每分鐘上限。`Retry-After` 會指出需等待的秒數。等待 `Retry-After` 指定的時間後,再以退避策略重試。
INTERNAL500非預期的伺服器錯誤。訊息刻意保持籠統;回報時請附上 `request_id`。幾秒後重試一次;若問題持續,請附上請求 ID 回報。
UPSTREAM_FAILED503此端點背後的資料來源未及時回應。不會以過期或替代的數字代替回傳。以退避策略重試;並查看狀態頁面。
UNAVAILABLE501 / 503資料集暫時尚未就緒(快取預熱中),或此端點目前尚無合法的公開來源。稍後重試;目錄會標示出設計上即無法使用的端點。
REQUEST_FAILED200部分舊版端點會以 HTTP 200 回應但帶有 `success: false`。請務必檢查 `success`,而不只是 HTTP 狀態碼。視訊息而定;請當作失敗的請求處理。
較舊的端點在項目不存在時,可能回傳 HTTP 200 搭配 success: false 與錯誤碼 REQUEST_FAILED。請對每個回應都檢查 success。

請求 ID

每個回應都帶有 X-Request-Id 標頭。失敗的回應還會在內容中以 request_id 重複這個值。由短效邊緣快取提供的回應,會沿用產生該回應之請求的 ID;因此連續呼叫若得到相同的 ID,代表你收到的是快取副本。

速率限制

限制以每分鐘計算:匿名呼叫依 IP 位址計,帶有有效 CB-API-KEY 標頭的呼叫則依金鑰計。上限為每分鐘 1200 次請求。/api/coin-icon 底下的圖示請求不計入。

速率限制標頭

名稱說明
X-Request-Id這次請求的識別碼。回報錯誤時請附上。
X-RateLimit-Limit目前這個一分鐘視窗內允許的請求數。
X-RateLimit-Remaining目前視窗內剩餘的請求數。
X-RateLimit-Reset視窗重設的 Unix 時間(秒)。
Retry-After隨 HTTP 429 送出:重試前應等待的秒數。
X-Cache伺服器端回應快取的狀態:HIT、STALE 或 MISS。

超過限制時

API 會回傳 HTTP 429 與錯誤碼 RATE_LIMITED。請等待 Retry-After 指定的秒數後再重試。輪詢頻率若高於端點的快取 TTL,只會拿到同一份快取回應,因此請依各參考頁面標示的 TTL 設定輪詢間隔。

以退避策略重試

JavaScript
async function getJson(url, tries = 4) {
  for (let i = 0; i < tries; i++) {
    const res = await fetch(url);
    if (res.status === 429 || res.status >= 500) {
      const wait = Number(res.headers.get("Retry-After")) || 2 ** i;
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    const body = await res.json();
    if (body.success === false) {
      throw new Error(body.code + ": " + body.error + " (" + body.request_id + ")");
    }
    return body;
  }
  throw new Error("gave up after " + tries + " attempts");
}

沒有資料不算錯誤

當參數有效、但該資料沒有合法的公開來源時,呼叫仍會成功並回傳 HTTP 200:數值欄位為 null,meta.quality 為 UNAVAILABLE,coverage.unavailable 則列出原因。請將它顯示為破折號,不要轉成 0。

過期資料

若採集器進度落後,端點會繼續提供最後儲存的數值並標示 meta.is_stale: true;一旦超過可用視窗,這些數值就會從彙總中剔除,並列入 coverage.stale_excluded。