错误响应设计

错误响应要机器可读且可追踪:统一结构包含类型、标题、状态、详情与实例标识(Problem Details),前端按类型分支处理,配合字段级校验信息。

错误响应设计是什么

错误响应要同时服务两类读者:机器要能稳定判断并分支处理,人要能看懂该做什么。通用做法是采用 Problem Details 结构(RFC 9457),用 type 标识错误类别、title 给出可读摘要、status 对应 HTTP 状态码、detail 描述本次具体情况、instance 指向本次请求的实例标识,便于用关联 ID 去日志与追踪里定位。字段级校验错误则需要结构化列出具体字段,前端才能准确高亮。

基本信息

标准结构type / title / status / detail / instance(Problem Details)
内容协商媒体类型 application/problem+json
状态码与结构一致:400 参数、401 未认证、403 无权限、409 冲突、422 校验失败、429 限流
关联标识instance 或 trace_id 与日志、追踪打通
安全边界不返回堆栈、SQL、内部主机名与内部错误码

典型使用场景

  • 表单提交失败:返回字段级错误列表,前端逐项高亮并给出修正提示
  • 幂等与并发冲突:版本不匹配返回 409 或 412,客户端拉取最新数据后重试
  • 限流与配额:返回 429 并在响应头给出重试建议时间
  • 依赖故障:区分「请求有错」与「服务暂时不可用」,让调用方决定是否重试
  • 第三方对接:错误码与结构稳定,集成方可以写出可靠的重试与告警逻辑
  • 排查定位:凭 instance 在日志系统中检索同一次请求的完整上下文

响应示例

响应示例
{
  "type": "https://errors.example.com/validation",   // 错误类别,客户端按此分支处理
  "title": "Validation failed",                      // 稳定摘要,不随单次请求变化
  "status": 422,                                      // 与 HTTP 状态码一致
  "detail": "field 'email' is invalid",               // 本次具体原因,可行动
  "instance": "/requests/7f3c9a52",                  // 关联标识,用于排查
  "errors": [                                         // 字段级错误清单
    {"field": "email", "code": "invalid_format", "message": "邮箱格式不正确"}
  ]
}

字段与澄清

字段作用常见问题
type机器可判别的错误类别直接写 URL 路径或随实现漂移,客户端无法稳定判断
title稳定的可读摘要把 detail 的内容写进 title,每次都在变
status与 HTTP 状态码一致结构与状态码不一致,网关与客户端处理冲突
detail本次请求的具体原因暴露内部实现细节或根本没有可行动信息
instance本次请求的关联标识缺失时无法把用户反馈与日志对上
错误信息分两套:给调用方的可行动提示与给内部的详细诊断。内部细节写日志并用关联标识串起来,不要把堆栈直接返回给调用方。
错误码一旦对外发布就属于契约:新增细分错误应并存原码或走版本策略,直接改语义会让客户端的重试与告警逻辑失效。

易错点

  • 把堆栈与内部标识返回给调用方:泄露实现细节,存在安全风险
  • 错误结构随接口随意变化:客户端无法统一处理,只能逐接口适配
  • 所有失败都返回 500 或统一 200 带错误体:网关、监控与重试策略全部失效
  • 校验错误只给一句「参数错误」:前端无法定位字段,用户反复试错
  • 错误响应未带关联标识:用户反馈时报出的现象无法在日志中定位

数据来源与参考

  • RFC 9457:Problem Details for HTTP APIs
  • Microsoft REST API Guidelines:Errors
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌