题干与适用场景
这道后端题考察 API 契约和故障边界。重点不是把所有异常包装成一个 JSON,而是让客户端能根据稳定的类型和状态采取动作,同时让日志、追踪、权限与用户文案保持分层。
面试官考察什么
- 是否理解
application/problem+json与 HTTP 状态码的关系。 - 是否能区分验证失败、认证授权、资源冲突、限流、暂时不可用和未知错误。
- 是否能设计字段级错误、可追踪实例和安全的扩展成员。
- 是否能避免泄露堆栈、内部 ID、个人信息和不可信的原始异常。
回答前需要澄清的问题
先确认客户端需要机器决策还是仅展示消息;是否有多语言、批量校验和异步任务;错误类型是否由跨服务共享;哪些状态可重试;以及网关、服务和客户端各自负责记录什么、展示什么和生成请求追踪 ID。
30 秒回答框架
我会使用 application/problem+json,以 type、title、status、detail 和 instance 作为稳定骨架,再用受控扩展表达错误码、字段路径、重试时间和文档版本。HTTP 状态表示通用语义,type 表示可编程分类;服务端日志保存内部原因,响应只返回安全、可行动的信息。
分步骤深入解答
1. 先建立状态码与类型边界
400 表示请求无法按语法或通用规则处理,401 表示需要认证,403 表示已识别但不允许,404 表示资源不存在,409 表示当前状态冲突,429 表示超出限流,5xx 表示服务端或依赖暂时失败。type 应是稳定、可文档化的 URI;不要让客户端只解析易变的 title 或 detail。
2. 设计 Problem Details 字段
type 用于程序分类,title 是稳定的人类摘要,status 复制响应状态,detail 解释当前请求,instance 关联这一次具体发生。扩展成员可包含 code、字段路径、参数名、重试时间或支持文档版本,但应限制词汇和长度。批量校验可返回错误数组,每项都指向输入位置。
3. 处理验证、冲突与重试
验证失败应让客户端知道如何修正字段,不应要求重试;冲突需要重新读取或改变业务动作;429 或依赖暂时不可用可提供 Retry-After,但客户端仍要遵守退避和上限。把可重试与不可重试作为明确契约,不要因为所有响应都是 200 就让客户端猜测。
4. 保护安全和隐私边界
响应不应包含堆栈、SQL、密钥、内部主机名、租户越权信息或完整个人数据。detail 只说明可行动的事实,instance 使用不可预测或受控的引用;内部日志通过请求 ID 关联原始异常。认证失败要避免通过错误文案泄露账户存在性,字段错误也要按权限过滤。
5. 保持跨服务和版本演进
把共享 type、状态和扩展写入版本化文档与契约测试,网关不要擅自改写服务语义。新增字段应向后兼容,废弃类型要提供迁移期;客户端遇到未知 type 应回退到 status 和安全 detail。通过错误类型分布、重试成功率、字段错误热点和请求 ID 追踪质量。
高质量示范回答
我会把所有错误响应声明为 application/problem+json,使用稳定的 type URI、title、status、detail 和 instance。400/401/403/404/409/429 与 5xx 按通用 HTTP 语义区分,验证错误增加字段路径和安全 code,429 或暂时依赖故障可带 Retry-After。客户端按 type 决定修正、重新读取、退避还是联系支持,不解析易变 detail。服务端日志保留堆栈、依赖状态和请求 ID,响应绝不泄露 SQL、密钥、租户信息或个人数据。共享类型和扩展做版本化与契约测试,未知 type 回退到 status;上线后监控错误类型、重试结果和字段热点。
常见错误
- 所有错误都返回 200 和一段文本,让客户端无法做机器决策。
- 让客户端依赖 title 或 detail 的字面文案,改一个翻译就破坏逻辑。
- 把验证失败、冲突、限流和暂时不可用都标成 500。
- 在 detail 中返回堆栈、SQL、内部主机名或完整用户数据。
- 用内部异常类名直接作为公开 type,导致实现细节变成长期契约。
- 没有未知 type 的回退策略和跨服务契约测试。
追问及应对
type 一定要是真实可访问的 URL 吗?
它应是稳定的 URI,通常可指向解释该问题的文档,但客户端不应依赖每次都能访问。重点是标识语义、版本和迁移说明,而不是把错误处理变成一次额外网络请求。
detail 需要做国际化吗?
机器字段和 type 保持稳定,用户可见文案由客户端按语言和场景渲染。若服务端必须返回 detail,应提供安全模板和语言协商,不能把未翻译的内部异常直接暴露。
网关应该统一改写错误吗?
网关可以补充请求 ID、超时和协议层错误,但不应抹平服务的业务 type。改写必须有版本化规则和观测,否则客户端看到的语义与真正失败原因会脱节。
如何处理批量请求中部分成功?
定义明确的批量结果模型,逐项返回状态、输入位置和可重试性,并说明整体 HTTP 状态代表什么。部分成功不能靠一个模糊的 detail 表达,也不能让客户端重复提交已成功项目。