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将变得可预测,安全且对集成商友好。