Skip to content
ADP
API Design PrincipleBETA

[ADP-138] 速率限制標頭

reviewing phase 1

應統一限流回應。

為什麼使用速率限制標頭?

  1. 確保沒有單一用戶或應用程式可以壟斷 API 資源,為所有用戶提供公平的訪問機會。
  2. 有助於保護後端基礎設施不會在短時間內被過多請求壓垮,這可能導致性能下降或停機。
  3. 向 API 消費者傳達他們當前的使用狀態和限制,幫助他們管理請求速率並避免意外的服務中斷。

速率限制標頭列表

根據 RFC 草案,應該實施以下標頭以有效傳達速率限制:

  1. X-RateLimit-Limit: 指示在給定時間段內允許的最大請求數。
  2. X-RateLimit-Remaining: 顯示當前時間段內剩餘的請求數。
  3. X-RateLimit-Reset: 指定速率限制計數器重置的時間,通常以 Unix 時間戳提供。
  4. Retry-After: 指示客戶端在超過速率限制後應等待多長時間才能再次發出請求。此處請參閱 ADP-139: Retry-After

指導原則

  • 速率限制標頭應該(SHOULD)在所有受速率限制的 API 端點上一致應用。
  • 在 API 文件中清楚地記錄速率限制政策,包括限制和每個標頭的含義。
  • 當超過速率限制時,伺服器應該(SHOULD)回應 429 (Too Many Requests) 狀態碼,並附帶 Retry-After 標頭以指示客戶端何時可以重試請求。
  • 應(SHOULD)根據不同端點或用戶層級的具體需求和使用模式定義速率限制。
  • 應(SHOULD)定期監控使用模式並根據需要調整速率限制,以確保最佳性能和用戶體驗。

錯誤回應格式 (RFC 9457)

當超過速率限制時,除了提供 X-Rate-Limit-* 系列標頭以外,伺服器應該按照 RFC 9457 中定義的標準化錯誤格式回應。以下是如何格式化此類回應的示例:

錯誤回應示例

http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 3600
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1625247600

{
  "type": "/problems/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded your rate limit. Please wait until the specified time before making further requests.",
  "instance": "/users/12345",
  "rateLimit": {
    "limit": 1000,
    "remaining": 0,
    "reset": 1625247600,
    "retryAfter": 3600
  }
}

回應欄位描述

  • type: 識別問題類型的 URI 引用。
  • title: 問題類型的簡短、人類可讀摘要。
  • status: 原始伺服器為此問題發生生成的 HTTP 狀態碼。
  • detail: 特定於此問題發生的人類可讀解釋。
  • instance: 識別問題特定發生的 URI 引用。
  • rateLimit: 包含速率限制詳細資訊的對象,包括:
    • limit: 允許的最大請求數。
    • remaining: 當前時間段內剩餘的請求數。
    • reset: 速率限制計數器重置的時間,通常以 Unix 時間戳提供。
    • retryAfter: 客戶端在超過速率限制後應等待的時間(以秒為單位),然後再發出另一個請求。

OpenAPI 規範示例

以下是如何在 OpenAPI 3.1.0 規範中記錄速率限制的示例:

yaml
openapi: 3.1.0
info:
  title: Example API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      responses:
        '200':
          description: Successful response
        '429':
          description: Too Many Requests
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: The number of allowed requests in the current period
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: The number of remaining requests in the current period
            X-RateLimit-Reset:
              schema:
                type: integer
              description: The number of seconds left in the current period
            Retry-After:
              schema:
                type: integer
              description: The number of seconds to wait before retrying the request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
components:
  schemas:
    Problem:
      type: object
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        rateLimit:
          type: object
          properties:
            limit:
              type: integer
            remaining:
              type: integer
            reset:
              type: integer
            retryAfter:
              type: integer

避免重複定義已知標頭

根據 ADP-767,你應該(SHOULD)使用已經定義好的共用標頭檔案或至少使用 #/components/headers,以避免重新定義所有已知標頭。

關聯 ADPs

參考資料