[ADP-138] 速率限制標頭
reviewing phase 1
應統一限流回應。
為什麼使用速率限制標頭?
- 確保沒有單一用戶或應用程式可以壟斷 API 資源,為所有用戶提供公平的訪問機會。
- 有助於保護後端基礎設施不會在短時間內被過多請求壓垮,這可能導致性能下降或停機。
- 向 API 消費者傳達他們當前的使用狀態和限制,幫助他們管理請求速率並避免意外的服務中斷。
速率限制標頭列表
根據 RFC 草案,應該實施以下標頭以有效傳達速率限制:
- X-RateLimit-Limit: 指示在給定時間段內允許的最大請求數。
- X-RateLimit-Remaining: 顯示當前時間段內剩餘的請求數。
- X-RateLimit-Reset: 指定速率限制計數器重置的時間,通常以 Unix 時間戳提供。
- 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
,以避免重新定義所有已知標頭。