题干与适用场景
一个 API 网关要求客户端改用 HTTP/3,但仍收到 HTTP/1.1 请求。请说明何时返回 426、响应应包含什么、客户端如何恢复,以及为什么不能把所有协议不匹配都返回 426。
HTTP 426 表示服务器拒绝使用当前协议处理请求,但客户端升级到另一个协议后可能成功。RFC 9110 给出的示例是响应中携带 Upgrade: HTTP/3.0。它表达的是可行动的协议升级要求,不是普通参数错误、TLS 握手失败或服务器完全不支持该资源。
面试官考察点
面试官会观察你是否准确引用 426 的语义,能否区分 Upgrade 头与 TLS、HTTP 版本协商,是否考虑缓存、代理、幂等重试、观测和客户端兼容性,并能解释 400、421、505 等相近状态码的边界。
回答前需要澄清的问题
先确认升级的是 HTTP 协议、TLS 连接还是应用层版本;确认客户端是否能建立目标协议、请求方法是否可安全重试、网关前是否有代理,以及升级后原请求是否需要重新发送。再确认是否有一部分租户仍必须使用旧协议,以及是否需要灰度和回滚。
30 秒回答框架
“只有服务器仍愿意在目标协议上处理同一资源,而当前协议阻止处理时,我才返回 426,并在响应中给出明确的 Upgrade 值和可读说明。客户端应重新建立目标协议连接,再按方法语义决定是否重试;不能假设请求已经执行或可以盲目重放。若服务器完全不支持该版本,使用 505;若是错误的连接路由,考虑 421;普通请求格式问题则用 400。网关还要记录协议、代理链和升级结果,避免缓存或重试放大流量。”
分步骤深入解答
第一步:确认 426 的触发条件
426 的关键是“当前协议不适用,但升级后可能成功”。服务器必须知道目标协议和升级路径,不能把未知客户端、缺失参数或应用版本落后都笼统归入 426。
第二步:构造可行动的响应
响应应包含 Upgrade 头,值列出服务器接受的目标协议,例如 HTTP/3.0,并提供简短正文或机器可读错误码。不要只返回模糊的“please upgrade”,也不要把敏感内部拓扑写入正文。
HTTP/1.1 426 Upgrade Required
Upgrade: HTTP/3.0
Content-Type: application/problem+json
{"type":"https://example.test/problems/upgrade-required","title":"Upgrade required"}第三步:区分连接升级与应用重试
客户端需要先建立目标协议连接,再决定是否重新发送原请求。连接升级是传输层或协议层动作,不能靠修改一个应用字段完成。对于 POST 等非幂等请求,客户端必须依据幂等键、服务端执行记录和 API 契约决定是否重试。
第四步:处理 TLS 场景
HTTP 426 不能替代 TLS 握手失败或证书错误。RFC 2817 讨论过在 HTTP/1.1 中升级到 TLS 的路径,但现代部署通常在连接建立阶段协商 TLS 和 HTTP 版本。若请求根本没有到达可生成 HTTP 响应的阶段,应记录握手错误,而不是伪造 426。
第五步:划清相近状态码
400 表示请求语法或内容无效;421 表示请求被发往无法产生响应的服务器;505 表示服务器不支持请求使用的 HTTP 版本。426 强调“升级后可能继续服务”,因此不能把完全不支持目标协议或资源不存在的情况包装成 426。
第六步:设计代理、缓存与重试策略
代理可能终止连接并重新发起请求,客户端也可能自动重试。响应应明确 Cache-Control 策略,避免旧协议错误被长期缓存;网关记录原始协议、协商结果、代理链和重试次数。重试预算必须与速率限制及熔断策略一致。
第七步:保护灰度与回滚
先对具备目标协议能力的客户端灰度,观察成功率、延迟、错误类型和重复写入,再扩大范围。保留旧协议入口直到迁移完成,并准备按客户端、租户或区域回滚策略。不要仅凭 426 数量判断迁移成功,因为中间代理可能吞掉或改写响应。
第八步:验证客户端恢复
测试 GET、幂等 PUT、非幂等 POST、长连接、代理转发、缓存命中、TLS 失败、未知升级值和目标协议不可用。验证客户端是否重新建连、是否重复写入、是否保留认证上下文,以及日志和指标是否能区分 426、421、505 与握手失败。
高质量示范回答
我会先确认当前协议确实阻止服务器处理请求,而目标协议可用并有明确升级路径。此时返回 426,带 Upgrade: HTTP/3.0 和机器可读错误信息;正文不泄露内部细节。客户端要重新建立 HTTP/3 连接,再按方法幂等性、幂等键和执行记录决定是否重试,不能假设原请求未执行。TLS 握手失败应在连接层处理,完全不支持 HTTP 版本应使用 505,错误路由考虑 421,语法错误使用 400。迁移通过客户端能力灰度,监控协议、代理链、重复写入和成功率,设置缓存和重试边界,并保留旧协议回滚入口。最后覆盖不同方法、代理、缓存、长连接和目标协议不可用的测试。
常见错误
把 426 当成所有客户端版本过旧的通用错误
426 针对协议升级,而且升级后服务器可能继续处理。应用版本过旧、缺少字段或权限不足应使用各自的业务错误契约。
认为加上 Upgrade 头就完成了升级
响应只是告诉客户端下一步,客户端仍需重新建立合适连接。服务器和代理还必须真正支持目标协议及认证、路由、限流和观测链路。
对非幂等请求自动重放
426 发生在请求处理边界附近,客户端不能凭状态码推断写入一定没有发生。没有幂等键或执行查询能力时,自动重放 POST 可能产生重复副作用。
追问及应对
426 与 505 的核心区别是什么?
426 表示升级后可能成功,响应会指向目标协议;505 表示服务器不支持请求使用的 HTTP 版本,通常没有可用的升级承诺。
代理把 HTTP/3 终止在边缘,源站还会返回 426 吗?
边缘代理应在能力和路由边界处理协商,并把必要上下文传给源站。若源站看不到真实客户端协议,不能仅凭连接字段做错误判断,应记录代理协议和转发语义。
426 响应可以缓存吗?
只有在明确知道缓存键、客户端能力和迁移策略时才考虑缓存。默认应避免让共享缓存长期保存协议迁移错误,并用响应头表达短时策略。
POST 收到 426 后如何安全恢复?
使用幂等键、服务端执行状态查询和客户端重试预算。先建立目标协议连接,再确认原请求是否已执行;无法确认时向用户报告待确认状态,而不是盲目重放。
什么时候应在连接层拒绝,而不是返回 426?
当 TLS、ALPN 或底层协议协商在生成 HTTP 响应前失败时,应在连接层关闭并记录原因。426 只适用于服务器能够发送 HTTP 响应、且升级建议可行动的场景。
如何证明协议迁移没有伤害用户?
按客户端能力灰度,比较 426 后成功率、延迟、重复写入、认证失败、代理分布和回滚耗时。指标要能区分边缘、源站和客户端重试,不能只看 426 总量。