后端面试:如何设计 HTTP 415 Unsupported Media Type 契约?
题干与适用场景
一个 API 的 POST 接受 JSON 和 CBOR,PATCH 接受 JSON Patch。客户端发送错误的 Content-Type、内容编码或 PATCH 文档格式时收到 415。请设计服务端判定、响应头、错误体、客户端恢复和版本演进。
这是后端 API 契约题。媒体类型和格式是题设,不代表线上频率。
面试官考察点
- 能否区分请求的 Content-Type、Content-Encoding 和响应的 Accept。
- 能否说明 415 的适用边界,而不是把所有解析错误都归入 415。
- 能否使用 Accept-Patch 暴露 PATCH 能力并保持兼容。
- 能否让错误响应可行动且避免自动重试副作用。
回答前需要澄清的问题
- 415 是因为媒体类型、内容编码还是该方法不支持该表示?
- 客户端是否能重新编码正文,是否有稳定请求 ID?
- PATCH 支持哪些文档类型和资源版本条件?
- 网关是否会改写 Content-Type、编码或错误体?
- 新媒体类型如何灰度,旧客户端如何继续工作?
30 秒回答框架
“415 表示目标方法拒绝处理当前请求表示的格式。服务端先解析 Content-Type、参数和 Content-Encoding,再按方法与资源能力选择解析器;Accept 描述客户端希望收到的响应格式,不是请求格式。PATCH 资源可用 Accept-Patch 声明支持的文档媒体类型。错误体返回稳定码、实际收到与允许值和请求 ID,客户端只在能重新编码且操作可安全重放时重试。我会用兼容矩阵和逐层指标验证演进。”
分步骤深入解答
1. 划分三个头部语义
Content-Type 描述请求正文的媒体类型,Content-Encoding 描述传输编码,Accept 描述客户端可接受的响应表示。服务端不能用 Accept 判断客户端发送的 PATCH 文档,也不能把解压失败、损坏正文和不支持媒体类型混成一个原因。
2. 建立方法与资源能力表
每个方法和资源绑定允许的媒体类型及参数。例如 POST 可接受 application/json 与 application/cbor,PATCH 只接受注册的 JSON Patch 文档。先检查类型和编码,再进入解析器;解析成功后仍要做 schema、权限和业务校验。
PATCH /documents/42 HTTP/1.1
Content-Type: application/json-patch+json
Accept: application/json
Content-Length: 1283. 返回准确的 415
媒体类型或内容编码不受支持时返回 415,并给出稳定错误码。若格式正确但字段无效,使用领域校验错误;若正文语法损坏,使用清晰的解析错误。响应中的 Accept 可说明服务端愿意返回的表示,不能把它伪装成请求媒体类型清单。
4. 暴露 PATCH 能力
RFC 5789 定义 Accept-Patch,资源可在 OPTIONS 或成功响应中声明支持的 PATCH 文档媒体类型。客户端据此选择 JSON Patch 等格式;服务端仍需在具体请求中验证资源版本、操作路径和权限。能力声明应与实际解析器保持一致。
5. 设计客户端恢复
客户端收到 415 后读取稳定错误码和允许类型,重新编码正文或切换到兼容端点。只有正文可重建、请求没有不可逆副作用、幂等键保持不变时才自动重试。不要因为 415 就重复提交已经可能成功的 PATCH,也不要把 415 当作服务暂时不可用。
6. 控制演进和观测
新增媒体类型先在网关、服务端和 SDK 中灰度,保留旧类型的兼容窗口。指标按资源、方法、收到的类型、编码、客户端版本和拒绝原因统计;记录请求 ID 与解析器版本,禁止记录敏感正文。发现网关改写头部时,分别比较入口和应用日志。
高质量示范回答
“我把请求格式和响应格式分开。服务端按方法与资源检查 Content-Type 和 Content-Encoding,解析成功后再做 schema 与业务校验;Accept 只用于协商响应。PATCH 资源通过 Accept-Patch 声明可接受的文档类型,实际请求仍要校验版本和权限。415 错误体给稳定码、收到值、允许值和请求 ID;客户端只有在可重编码且安全重放时才重试。新类型通过兼容矩阵和指标灰度,避免网关或旧 SDK 改写语义。”
常见错误
- 用 Accept 判断请求正文 → 混淆请求和响应协商 → 检查 Content-Type 与 Content-Encoding。
- 所有解析失败都返回 415 → 客户端无法判断修复路径 → 区分媒体类型、语法和领域校验。
- 声明 Accept-Patch 却没有对应解析器 → 能力契约失真 → 让声明与实际实现同源验证。
- 收到 415 自动原样重试 → 永远失败或重复副作用 → 先改编码并确认可重放。
- 只在应用记录类型 → 网关改写后无法定位 → 比较逐层头部和请求 ID。
追问及应对
Content-Type 正确但 Content-Encoding 不支持,仍然是 415 吗?
RFC 9110 将不接受的请求内容编码纳入 415 的适用范围。错误体应指出编码原因,客户端先解压或改用服务端支持的编码,再依据幂等与正文可重建性决定是否重试。
为什么不能只返回允许类型列表?
列表不说明当前方法、参数或版本约束。稳定错误码、收到值、允许范围、请求 ID 和文档链接更能驱动客户端修复,同时避免暴露内部实现细节。
如何安全增加 CBOR 支持?
先在非关键资源启用,验证网关透传、解析器资源上限、schema 等价性和日志脱敏;保留 JSON 回退,并按客户端版本观察 415、解析失败和业务结果差异。