1. 题目
一款 B2B 数据 API 服务了数千个开发者团队。最近一个版本上线后,支持工单中出现大量“请求失败但不知道怎么改”的反馈;工程团队认为返回更多内部日志即可解决,销售团队则要求每个客户定制错误文本。你作为产品经理,需要在不破坏现有客户端的前提下,设计一套可操作的 API 错误体验。
2. 约束与澄清
- 先区分客户端输入错误、认证授权、限流、依赖故障和服务内部错误,不能把所有失败合并成一个 500。
- 明确错误响应要同时服务机器处理、开发者排查和最终用户展示三类读者。
- 现有 SDK 和日志格式不能立即全部升级;方案需要兼容旧客户端并支持渐进迁移。
- 不能把敏感堆栈、令牌、用户数据或内部拓扑直接返回给调用方。
3. 产品诊断框架
先把问题拆成“发生了什么、谁能修、下一步是什么”三个层次。错误响应应有稳定的机器可读代码、面向人的安全摘要、可选的结构化详情和支持关联 ID;文档与 SDK 需要把代码映射到修复动作。产品分析不只看错误率,还要看错误后恢复成功率、重复重试率、从失败到成功的时间、每类错误的支持工单和版本分布。
4. 参考方案
errorResponse:
status: canonicalStatusCode
code: stableProductErrorCode
message: safeHumanSummary
details:
reason: machineActionableReason
fieldViolations: optionalFieldErrors
retryAfter: optionalDelay
requestId: supportCorrelationId
docsUrl: versionedFixGuide
clientFlow(error):
classify(error.status, error.code)
if retryable: backoffAndRetry(error.details.retryAfter)
else if fieldError: highlightFields(error.details.fieldViolations)
else: showDocsAndRequestId(error.docsUrl, error.requestId)先定义少量稳定的通用状态码,再用产品错误代码表达可行动的原因;字段错误、重试时间和文档链接放在结构化详情中。控制台按代码展示修复步骤,SDK 将错误映射为可捕获的类型,同时保留原始代码。服务端记录完整诊断信息,但只把安全摘要和关联 ID 返回给调用方。
5. 取舍与发布策略
错误代码越细,修复指引越精确,但版本兼容和文档维护成本越高。可以先覆盖高频、可由开发者修复的错误,再为少数客户问题补充详情,不为每个租户定制协议。新增字段应向后兼容;代码语义一旦公开就应保持稳定,旧代码继续返回旧格式,新 SDK 再启用结构化详情。局部失败响应需要谨慎设计,因为它会增加客户端分支,只有批量 API 明确需要时才引入。
6. 验证与观测
- 从支持工单和调用日志抽样,给每类失败标注“能否定位、能否修复、是否重复重试”。
- 对认证、字段校验、限流、依赖超时和未知异常分别编写契约测试,验证状态码、错误代码和文档链接。
- 灰度新格式,比较错误后恢复率、重复重试率、支持工单量和 SDK 异常捕获率。
- 监控未知错误代码、旧客户端占比、文档点击到成功请求的转化,以及错误响应是否泄露敏感字段。
7. 常见误区
- 只增加日志或堆栈,却没有给调用方稳定代码和修复动作。
- 用 HTTP 状态码承载所有业务语义,导致客户端只能按字符串解析。
- 为了“友好”把内部异常、令牌或完整请求参数放进错误消息。
- 一次性重命名或删除错误代码,迫使旧 SDK 在升级时失效。
8. 面试评分点
能按修复责任分类错误
应区分输入、权限、限流、依赖与内部故障,并说明每类错误的调用方动作和服务方责任。
能设计稳定且安全的错误模型
应提出机器可读代码、安全摘要、结构化详情、关联 ID 和版本化文档,同时避免泄露内部信息。
能把体验连接到产品指标
应使用恢复成功率、重复重试、修复时间、工单和版本分布衡量价值,而不是只看失败率。
能规划兼容迁移
应说明旧格式兼容、新 SDK 渐进启用、灰度发布和回滚条件,并解释何时不采用局部失败等复杂协议。