GH GambleHub

错误处理和状态代码

1)为什么要标准化错误

单一错误合同加快了客户调试,减少了虚假的重复并使RCA可播放。良好的系统:
  • 可以预见地编码问题的类型,
  • 向客户提供有效的提示(接下来要做什么),
  • 防止内部零件泄漏,
  • 与复古和幂等兼容。

2)设计原则

1.所有服务的一个错误模式(REST/GraphQL/gRPC/webhooks)。
2.清晰的retrae语义:哪些代码是retra,哪些不是。
3.在写操作上失效:优于4xx/5xx而不是安静的非约束。
4.不泄漏:不披露SQL、堆栈、configs、内部ID。
5.跟踪:始终返回'trace_id'/'correlation_id'。
6.消息本地化-可选,但代码和"reason"保持稳定。


3)统一格式(问题详细信息/JSON)

推荐的基本格式(与RFC 7807兼容):
json
{
"type": "https://errors.example.com/auth/invalid-token",
"title": "Invalid access token",
"status": 401,
"code": "AUTH_INVALID_TOKEN",
"detail": "Token expired or signature invalid.",
"instance": "/api/v1/payments/12345",
"trace_id": "01HX3...ABC",
"hint": "Obtain a new token via OAuth2 refresh.",
"meta": {
"scope": "payments:write",
"policy": "deny-by-default"
}
}
说明:
  • "类型"是错误类的稳定URL ID。
  • "代码"是短域机器代码(版本之间稳定)。
  • "hint"-客户端要做什么(重播、更新令牌、更改设置)。
  • "meta"是安全的细节(没有秘密和PII)。

4)状态代码映射(最低设置)

身份验证/授权

400 Bad Request是结构验证/方案。
401 Unauthorized-无/非验证令牌。添加"WWW-Authenticate"。
403 Forbidden-已身份验证,但没有权利/政策被拒绝。
404 Not Found-在没有权限的情况下掩盖资源的存在。
409冲突是版本/状态冲突(optimistic lock,等效性)。
451 Unavailable For Legal Reasons是一个合规性/管辖区块。

限制和保护

408 Request Timeout-客户端发送主体的速度太慢。

409/425 Too Early-第一0-RTT/TLS禁止早期重播。3.

429 Too Many Requests-带有"Retry-After"和限制政策。
499 Client Closed Request-(在外围/NGINX)客户端断开连接。

数据和业务规则

422 Unprocessable Content-业务验证已通过该方案,但含义不正确。
423 Locked-资源锁定(KYC review, AML freeze)。
409冲突是双重发送,竞赛,状态限制(例如,"已经在处理中")。
410 Gone-已删除端口/资源(删除已完成)。

服务器

500 Internal Server Error-未知错误;不要透露细节。
502 Bad Gateway-依赖性返回错误/滚动。
503 Service Unavailable-退化/计划工作;添加"Retry-After"。
504 Gateway Timeout-依赖时间。

💡 规则:write操作,如果有疑问→ 409(冲突)或503(重播后),不是200。

5)静止和静止语义

无法转发:400/ 401/403/404/422(如果客户没有更改请求)。
可以转发:408/429/5xx/ 425/499/504(带有backoff+jitter)。
相似性:对于"POST",请启用"Idempotency-Key"(UUIDv4)。

对于重新运行冲突,请返回409,并带有"hint:使用字符标识-键或GET状态"。
返回保存的结果时添加"Idempotency-Replay: true"。

429的头部示例:

HTTP/1.1 429 Too Many Requests
Retry-After: 3
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1730641030

6)入口验证: 字段错误结构

对于400/422,请使用字段错误数组:
json
{
"type": "https://errors.example.com/validation",
"title": "Validation failed",
"status": 422,
"code": "VALIDATION_ERROR",
"trace_id": "01HX4...XYZ",
"errors": [
{"field": "amount", "rule": "min", "message": "Must be >= 10"},
{"field": "currency", "rule": "enum", "message": "Unsupported currency"}
]
}

7)部分失败(batch/partial failure)

在战斗结束中,不要在没有结构的情况下将错误隐藏在200内。返回207 Multi-Status或200 c结果阵列,其中每个作业都有自己的状态:
json
{
"status": "partial",
"succeeded": 8,
"failed": 2,
"results": [
{"id": "op1", "status": 201},
{"id": "op2", "status": 422, "error": {"code":"VALIDATION_ERROR","detail":"..."}}
]
}

8)分割和"空白"答案

空白收藏是200,带有"items:[]",不是404。
页面结尾为"next_page_token"。
不正确的令牌是400 code: PAGINATION_CURSOR_INVALID'。


9) Webhooks: 可靠的交付

签署事件(HMAC)并在处理前检查。
成功处理的答案是2xx(优于204)。
收件人的时间故障为5xx;发件人重复(指数backoff,jitter)。
通过"event_id"进行重复数据消除并保存结果(idempotent consumer)。
payload无效-400/422,没有重复。


10)协议合规性(gRPC/GraphQL)

gRPC → HTTP:

`INVALID_ARGUMENT` → 400

`UNAUTHENTICATED` → 401

`PERMISSION_DENIED` → 403

`NOT_FOUND` → 404

`ALREADY_EXISTS` → 409

`FAILED_PRECONDITION` → 412/422

`RESOURCE_EXHAUSTED` → 429

`ABORTED` → 409

`UNAVAILABLE` → 503

`DEADLINE_EXCEEDED` → 504

GraphQL:在传输层中始终允许200个,但在"errors[]"中放置错误,并在标题/扩展中复制:
json
{
"data": { "createPayment": null },
"errors": [{
"message": "Forbidden",
"extensions": { "code": "FORBIDDEN", "status": 403, "trace_id": "..." },
"path": ["createPayment"]
}]
}

对于严重错误,建议不要使用200,而是使用相应的HTTP代码。


11)标题和提示客户

"Retry-After"-秒/NTTR日期(429/503/425/408)。
"警告"是软降解或去除("199-Feature X已去除")。
`Deprecation`, `Sunset`, `Link: <...>;rel="deprecation"'-用于受控断开连接。
"问题类型"(定制)-快速路由客户端上的错误。
"X-Trace-Id"/"Correlation-Id"-链接徽标/Trays。


12)通讯安全

不要重复响应主体中的输入秘密(令牌/签名)。
伪装PAN/PII('1234')。
对于401/403,请勿透露失败的属性。
对于404,而不是"资源输出而不是您自己"-只是404。


13)错误的可观察性

度量标准:
  • `http_errors_total{status, route, tenant}`
  • 'error_classes_total {code}(来自主体的'code')
  • 429, 5xx; 'p95'/'p99 'latency分配给错误答案
  • 'retry_after_seconds_bucket'-重复提示直方图
Logi/Traces:
  • 将响应链接到"trace_id",存储"code","type","status","route","tenant",而不存储PII。
Alerts:
  • RPS> N下的'5xx_rate> X%'激增;
  • 在关键路线上增加429条;
  • 依赖关系中的"timeout/504";
  • 频繁的409/偶数 →比赛的标志。

14)示例

14.1,422(业务验证)

json
{
"type": "https://errors.example.com/payments/limit-exceeded",
"title": "Limit exceeded",
"status": 422,
"code": "PAYMENT_LIMIT_EXCEEDED",
"detail": "Daily withdrawal limit reached for KYC1.",
"hint": "Increase limits after KYC2 or try tomorrow.",
"trace_id": "01J5...XYZ"
}

14.2 409(等容)


HTTP/1.1 409 Conflict
Idempotency-Replay: true
json
{
"type": "https://errors.example.com/idempotency/replay",
"title": "Duplicate request",
"status": 409,
"code": "IDEMPOTENT_REPLAY",
"detail": "A request with the same Idempotency-Key was already processed.",
"hint": "Reuse the same Idempotency-Key and GET the operation status."
}

14.3,429(限额)

json
{
"type":"https://errors.example.com/rate/too-many-requests",
"title":"Too many requests",
"status":429,
"code":"RATE_LIMITED",
"detail":"Per-key rate limit exceeded.",
"hint":"Retry after the time specified in Retry-After header."
}

15)反模式

返回200和主体中的错误文本。
在服务之间溷合不同的错误格式。
在"详细信息"中披露堆栈/SQL/表名/内部 URL。
使用"消息"代替稳定的"代码"/"类型"。
在预期业务错误时返回500(例如,"资产负债表不足")。
REST/GraphQL/gRPC之间的语义不一致。


16) iGaming/财务细节

KYC/AML/制裁的明确代码是:"KYC_REQUIRED","KYC_REVIEW","AML_LOCK","SANCTION_BLOCKED"。
管辖权限制:451,措辞安全,没有指定清单。
现金写作交易:409/423在竞争和锁定中,带有重播窗口的"hint"。
玩家限额不变量:使用422违反负责任支付规则。
审计:不变的决策日志(代码、时间、演员、trace_id)。


17)准备就绪支票清单

  • 单个JSON误差图,稳定的"类型"/"代码"。
  • Mapping HTTP ↔ gRPC/GraphQL是一致且有记录的。
  • retrae+"Retry-After"的语义;write的等效性。
  • 伪装PII/秘密;404用于隐藏资源。
  • 错误和异常度量;以"trace_id"表示。
  • Deprecate政策:"Deprecation","Sunset","Link"。
  • 测试:negative/fuzz,版本冲突,依赖性下降,双次提交。
  • 海德客户:回收和处理409/422/429/5xx。

18) TL;DR

将单个JSON错误格式c'type'/'code'/'trace_id'标准化,使用正确的HTTP代码,区分验证(400/422), (401/403/404)、冲突/等效性(409)和限制(429)。让我们明确的"Retry-After"和"hint",掩盖敏感数据,用"trace_id"绘制错误,并在5xx/429/p99上构建变量。

Contact

联系我们

如需任何咨询或支持,请随时联系我们。我们随时准备提供帮助!

开始集成

Email — 必填。Telegram 或 WhatsApp — 可选

您的姓名 可选
Email 可选
主题 可选
消息内容 可选
Telegram 可选
@
如果填写 Telegram,我们也会在 Telegram 回复您。
WhatsApp 可选
格式:+国家代码 + 号码(例如:+86XXXXXXXXX)。

点击按钮即表示您同意数据处理。