题干与适用场景
客户端请求一个启用透明内容协商的资源,服务端返回 HTTP 506 Variant Also Negotiates。系统含 Apache 风格协商、反向代理和缓存。请解释 506 的语义、触发循环、诊断路径、缓存策略和回退方案。
面试官考察点
- 是否知道 506 源自 RFC 2295 的透明内容协商。
- 能否区分协商循环、406 Not Acceptable 与代理 502。
- 是否会检查 Alternates、Variant-Vary、TCN 等响应元数据。
- 是否能定义客户端重试、缓存和降级边界。
- 是否考虑循环检测、观测和配置发布门禁。
回答前需要澄清的问题
确认请求的 Accept/Accept-Language、资源是否为 variant list、哪个层生成 506、是否经过代理缓存,以及客户端是否能接受固定 representation。信息不足时,假设代理将 variant 选择再次指向同一个协商资源。
30 秒回答框架
506 表示透明内容协商在选择 variant 时形成循环,服务器无法得到最终 representation。先从响应链和协商元数据确认循环,而不是把它当成普通上游错误。客户端对相同配置不应盲目重试,可请求固定资源或不带协商的 representation。服务端限制协商深度、修正 variant 配置,并监控 506 与 406 的分布。
分步骤深入解答
1. 解释透明协商
RFC 2295 允许 origin server 发布可选 variant,用户代理和中间节点依据请求头选择 representation。协商元数据描述候选和 Vary 维度,但最终请求必须收敛到一个具体资源。
2. 识别 506 循环
若 variant 本身仍指向需要透明协商的资源,选择过程会回到原始对象,形成循环。记录 resource URI、variant URI、协商代理、请求 id 和 visited 集合;再次访问同一节点即可证明环。
3. 区分相邻状态码
406 表示已有表示无法满足客户端条件,不一定存在循环。502 表示网关从上游获得无效响应。506 需要关注协商层闭环;不要仅依据边缘代理最后一个状态码判断根因。
4. 设计客户端回退
相同 Accept 条件和配置下重试不会消除循环。客户端可请求固定 variant、移除透明协商扩展,或提示服务端修复;只有配置变更或明确瞬时信号时才在预算内重试。
5. 处理缓存与 Vary
缓存键必须包含实际参与协商的 Vary 维度,不能把 506 当成任意 representation 的长期结果。错误响应是否可缓存按服务器 Cache-Control 决定;修复配置后需考虑旧缓存和代理刷新。
6. 服务端修复与安全
发布器在上线前构建 variant 图并做环检测,限制协商深度和时间。响应只返回关联 id,不暴露内部 URI 图。代理保留原始状态、Via 和 trace id,防止重写掩盖根因。
7. 验证与观测
测试自循环、两节点循环、深但无环列表、不同 Accept、语言变化、代理缓存、配置灰度和回滚。监控 506/406 比例、协商耗时、fallback、缓存命中和修复时长。
高质量示范回答
506 是 RFC 2295 透明内容协商的循环错误。variant 选择再次指向协商资源时,服务器无法得到最终 representation。我会记录 URI、variant、协商代理和 request id,用 visited 集合证明循环,并保留每跳原始状态和 trace。
客户端对相同条件快速失败,不进入盲目重试;可以请求固定 variant 或不使用透明协商。服务端发布前构建 variant 图做环检测,限制深度和时间,校验 Vary 与缓存键。验收覆盖 Accept/语言变化、代理缓存、灰度、回滚及 506 与 406 的区分。
常见错误
- 把 506 当作 406 或 502 的别名。
- 只看最终代理状态,不追踪 variant 图。
- 对同一协商配置无限重试。
- 缓存键没有包含 Vary 维度。
- 发布前没有做环检测和深度限制。
- 错误响应暴露内部 variant URI。
追问及应对
追问一:506 与 406 的关键区别是什么?
406 是没有可接受表示;506 是协商过程本身形成循环,资源选择无法收敛。
追问二:客户端可以重试 506 吗?
相同请求配置下不应重试。只有配置已修复或服务端明确给出瞬时信号时,才在预算内重试。
追问三:如何证明不是代理改码?
比较每跳 trace、Via、原始状态和协商头;必要时直连 origin 复现并对照边缘响应。
追问四:错误响应要不要缓存?
遵循 Cache-Control 与缓存策略,避免把协商循环扩大;修复后清理受影响的旧缓存。