错误体为什么重要
只看状态码往往不够:同一个 409 可能是重复提交,也可能是状态冲突,客户端要能按机器可读的错误码分流。RFC 9457 定义的 Problem Details(媒体类型 application/problem+json)取代了早期的 RFC 7807,是跨语言、跨团队的通用约定。
三个必备要素
即使用不上标准格式,错误体也至少要包含三样东西:稳定的错误码(不随文案改)、人类可读的说明、请求追踪 ID。缺了追踪 ID,线上问题就只能靠时间猜;缺了稳定错误码,客户端只能靠字符串比较做判断,改一次文案就全线崩。
基本信息
| 标准 | RFC 9457 problem+json(取代 RFC 7807) |
|---|---|
| 字段 | type、title、status、detail、instance,可加自定义扩展 |
| 媒体类型 | application/problem+json |
| 常见扩展 | errors 字段级校验信息、trace_id 追踪标识 |
典型使用场景
- 表单校验失败:用 422 加字段级错误,前端能精确定位到输入框
- 网关与各后端统一错误格式:SDK 只需实现一次解析逻辑
- 幂等键冲突:用稳定错误码让客户端决定重试还是提示用户
- 线上告警关联:错误体里的追踪 ID 直接跳到日志与链路系统
Problem Details 示例
Problem Details 示例
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/validation",
"title": "Validation failed",
"status": 422,
"detail": "email format invalid",
"instance": "/requests/01J2ABCD",
"errors": {"email": ["must be email"]}
}各层承载什么
| 层次 | 承载什么 | 不该做什么 |
|---|---|---|
| HTTP 状态码 | 粗粒度结果,供网关、缓存、监控统一处理 | 不要用 200 承载业务失败 |
| type 字段 | 稳定错误类别,供客户端分支判断 | 不要随文案或版本改动 |
| title 与 detail | 人类可读说明,可本地化 | 不要暴露堆栈、SQL 或内部路径 |
| instance 与追踪 ID | 定位某一次具体请求 | 不要省略,否则线上无法关联日志 |
把失败塞进 200 加一层 code 字段是常见做法,但它会让缓存、重试、监控全部失去通用语义。非网关类场景优先用真实状态码配 problem+json。
detail 里回显用户输入时注意转义与脱敏:错误体常被前端直接渲染,未转义会成为反射型注入的入口。