API錯誤代碼和最佳實踐
1)為什麼要標準化錯誤
客戶可預測性:統一格式和轉發行為。
加速debag: 'trace_id'/' request_id'、穩定'error_code'。
安全性:不泄露SQL/堆棧軌道/密碼。
可觀察性:報告錯誤分類法(驗證、配額、時間表等)。
2)基本原則
1.所有4xx/5xx的統一響應格式(以及部分錯誤的2xx是單獨的電路)。
2.明確的HTTP語義:正確狀態是最重要的。
3.兩個代碼級別:傳輸(「狀態」)和域穩定「error_code」。
4.Retriable vs Non-retriable:明確指出,讓我們給出背靠背的提示。
5.默認安全性:詳細信息僅限於具有權限的客戶端;沒有內部軌道。
6.本地化: 機器代碼保持穩定,文本翻譯.
3)單一錯誤格式(基於RFC 7807)
推薦的JSON(擴展的「application/problem+json」):json
{
"type": "https://api. example. com/errors/validation_failed",
"title": "Validation failed",
"status": 422,
"error_code": "VAL_001",
"detail": "Field 'email' must be a valid address",
"instance": "req_01HZY...93",
"trace_id": "a1b2c3d4e5f6",
"retriable": false,
"errors": [
{"field": "email", "code": "email_invalid", "message": "Invalid email"}
],
"hint": "Fix payload and retry",
"meta": {"docs": "https://docs. example. com/errors#VAL_001"}
}
強制性:「type」、「title」、「status」、「error_code」、「trace_id」。
可選:「errors[]」(通過字段),「retriable」,「hint」,「meta」。
- `Content-Type: application/problem+json`
- `X-Request-ID`/`Traceparent` (W3C)
- (對於429/503)「Retry-After」(秒或日期)
4)HTTP狀態語義(「經典」和實踐的融合)
2xx(成功與細微差別)
200 OK是通常的成功。
201 Created-創建資源(位置)。
202 Accepted-異步在隊列中(給予「status_url」)。
207 Multi-Status-部分成功(如果可以避免)。
4xx(客戶端錯誤)
400 Bad Request是語法/格式,但不驗證字段(優於422)。
401 Unauthorized-無/不正確的令牌。讓我們來「WWW-Authenticate」。
403 Forbidden是validen令牌,但缺少權利(RBAC/ABAC/限制)。
404 Not Found-沒有資源/端點。
409沖突-版本/狀態沖突(optimistic locking, idempotency)。
410 Gone-終端已永久刪除。
412 Precondition Failed-ETag/If-Match未通過。
415 Unsupported Media Type是錯誤的「內容類型」。
422 Unprocessable Entity-驗證業務規則。
429 Too Many Requests-超過配額/速度(見第7條)。
5xx(服務器錯誤)
500 Internal Server Error-突然錯誤;不要透露細節。
502 Bad Gateway是apstrim錯誤。
503 Service Unavailable-降解/過熱,給出「Retry-After」。
504 Gateway Timeout是後端的定時器。
5)域分類法「error_code」
我們推薦以下範圍:- 「AUTH_」-身份驗證/授權。
- 「VAL_」是輸入數據的驗證。
- 「RATELIMIT_」-配額和速度。
- 「IDEMP_」是冪等/重復。
- 「CONFLICT_」是版本/狀態。
- 「DEP_」-依賴項(PSP/DNS/SMTP)。
- 「PAY_」是支付域的業務錯誤。
- 「SEC_」-安全性(簽名,HMAC,mTLS)。
- 「INT_」是內部突發事件。
- 時間穩定性(back-compat)。
- 錯誤目錄中的說明和示例(docs+machine-readable JSON)。
6) Retriable vs Non-retriable
字段:- `retriable: true|false`
- 如果「true」是「Retry-After」(以秒為單位)或合同「指數後退(從1-2 s開始,最大為30-60 s)」。
Retriable通常是:「502/503/504」,一些「500」,「429」(窗口後)。
Non-retriable: `400/401/403/404/409/410/415/422`.
7) Rate limit"a錯誤(429)
身體是:json
{
"type": "https://api. example. com/errors/rate_limited",
"title": "Rate limit exceeded",
"status": 429,
"error_code": "RATELIMIT_RPS",
"detail": "Too many requests",
"retriable": true
}
標題:
- `Retry-After: 12`
- `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`
- Для квот: `X-Quota-Limit`, `X-Quota-Remaining`, `X-Quota-Reset`
8)相似性和沖突
在記錄請求中,「Idempotency-Key」(在24-72小時內是唯一的)。
重復操作沖突→ 409沖突與'error_code: 'IDEMP_REPLAY"'。
ETag → 412 Precondition Failed上的資源版本沖突。
在回復中,附加「resource_id」/「status_url」以進行安全重復查詢。
9)驗證和422
按字段返回錯誤列表:json
{
"status": 422,
"error_code": "VAL_001",
"errors": [
{"field":"email","code":"email_invalid","message":"Invalid email"},
{"field":"age","code":"min","message":"Must be >= 18"}
]
}
規則:
- 不要重復相同的400-422最好是業務驗證。
- 信息是人類的;「代碼」是機器的。
10)錯誤安全性
從不:堆棧軌道、SQL、文件路徑、私有主機名。
編輯PII;註意GDPR/DSAR。
對於簽名/NMAS:區分「SEC_SIGNATURE_MISMATCH」 (403)和「SEC_TIMESTAMP_SKEW」 (401/403)「檢查時間± 5分鐘」。
11)相關性和可觀察性
始終添加「trace_id」/「X-Request-ID」並滾動到logi/traces中。
將錯誤匯總為「error_code」和「status」 →「頂級錯誤」,「new vs known」。
Alerts: 5xx/422/429,潛伏期,分享錯誤。
12) gRPC/GraphQL/Webhooks-mappings
gRPC ↔ HTTP
GraphQL
運輸200,但內部的「errors[]」-添加「擴展」。code` и `trace_id`.
對於「fatal」(身份驗證/配額)-更好的實際HTTP 401/403/429。
Webhooks
僅將2xx收件人視為成功。
帶有指數支持的Retrai,「X-Webhook-ID」,「X-Signature」。
410從收件人停止retrai(已刪除endpoint)。
13)錯誤驗證
「類型」/「error_code」-穩定;新的-僅添加。
更改主體模式時-提升次要版本的API或'problem+json;v=2`.
文件:代碼表+示例;changelog錯誤。
14)文檔(OpenAPI片段)
全球對策
yaml components:
responses:
Problem:
description: Problem Details content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
schemas:
Problem:
type: object required: [type, title, status, error_code, trace_id]
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
error_code: { type: string }
detail: { type: string }
instance: { type: string }
trace_id: { type: string }
retriable: { type: boolean }
errors:
type: array items:
type: object properties:
field: { type: string }
code: { type: string }
message: { type: string }
Endpoint示例
yaml paths:
/v1/users:
post:
responses:
'201': { description: Created }
'401': { $ref: '#/components/responses/Problem' }
'422': { $ref: '#/components/responses/Problem' }
'429': { $ref: '#/components/responses/Problem' }
'500': { $ref: '#/components/responses/Problem' }
15)測試和質量
合同測試:符合「application/problem+json」(必填字段)。
Negative tests:所有分支401/403/404/ 409/422/429/500。
混亂/後退:在5xx/ 503/504/429(「Retry-After」)上檢查後退。
安全測試:沒有內部消息,正確的PII掩碼。
Backward-copat:老客戶了解新字段(添加,不要中斷)。
16)實施支票
- 單個'problem+json'+穩定'error_code'。
- 正確的HTTP/gRPC/GraphQL語義。
- Retriable/non-retriable+「Retry-After」/支持建議。
- 限額標題和429種行為。
- 相同性(「Idempotency-Key」,409/412)。
- 安全:無堆棧軌道/秘密,PII編輯。
- 所有錯誤中的「trace_id」/「X-Request-ID」。
- 錯誤目錄文檔和示例。
- 錯誤分類監測。
- 負面場景的自動測試。
17)迷你常見問題
400與422有什麼不同?
400是斷開的查詢(語法/內容類型)。422是語法有效的,但是業務規則沒有通過。
401什麼時候,403什麼時候?
401-無/錯誤令牌;403-代幣是,沒有足夠的權利。
總是需要「Retry-After」嗎?
429/503是的;對於其余的retriable-最好提出明確的建議。
底線
設計良好的錯誤是合同:正確的HTTP狀態,單個「問題+json」,穩定的「error_code」,明確的回避提示和嚴格的安全性。標準化格式,記錄分類法,添加遙測和測試-並且API將變得可預測,安全且對集成商友好。