摘要

  • RFC 2774 要求带强制扩展的请求把 GET 改成 M-GET、把 PUT 改成 M-PUT;不了解框架的服务器会遇到陌生方法,而不能悄悄忽略关键条件后执行原方法。
  • 支持框架的接收方若无法满足扩展策略,就返回 510;若确已理解并遵守全部强制声明,则用 Ext 或 C-Ext 确认。该实验后来转为 Historic,相关状态码与字段如今均已废弃。

最像成功的失败

设想客户端要用 PUT 写入一个资源,同时要求一项扩展执行额外约束。新服务器识别声明,先应用约束,再完成写入。旧服务器只认识 PUT,把陌生字段当作可忽略信息,仍然写入同样的字节并返回 200 OK。

两次传输都成功,业务含义却不同。第二台服务器没有拒绝请求,也没有报错;它以旧语义完成了一个发送方只愿意在新语义下执行的动作。宽容解析在这里不再促进兼容,而是把“不理解”伪装成“已完成”。

RFC 2774 在 2000 年 2 月以 Experimental 身份发布,目标就是切断这条隐蔽路径。它最醒目的设计不是 510,而是改变方法名。只要请求含有强制扩展,方法就必须带 M- 前缀。不了解该框架的服务器看到 M-PUT 时,应把它当作未知方法拒绝,而不是误执行基础 PUT。

把不兼容变成安全边界

支持框架的接收方也不能简单删掉前缀。它要先找出所有强制声明,判断每项扩展是否适用于当前消息,再执行扩展规则与基础 HTTP 方法。只要有一项无法支持,就必须返回 510 Not Extended。规范还明确禁止服务器在没有理解并遵守全部强制声明时声称请求已满足。

这是一种刻意制造的不兼容。通常,协议希望旧实现尽量接受新消息;但当新信息决定操作是否有效时,“尽量接受”反而会吞掉发送方的底线。M- 让无知先于副作用暴露出来。

四条声明通道

框架用两个维度划分扩展。强度上分为强制和可选,作用域上分为端到端与逐跳。由此形成 Man、Opt、C-Man、C-Opt 四个字段。

端到端声明的最终接收者是源站。代理能看到它,并不意味着代理有权消费它。逐跳声明只约束当前连接的下一方;在 HTTP/1.1 中,它及关联字段必须列入 Connection,避免被错误转发为端到端信息。

每个扩展由全局唯一的 URI 标识;在更窄的条件下,也可使用标准定义的字段名。声明还能分配一个数字前缀,例如 16。同一消息里,以 16- 开头的字段就归这个扩展实例所有。数字命名空间防止不同扩展撞名,也允许一个扩展出现多次,却不会霸占整个 HTTP 字段空间。

框架本身不规定扩展的业务含义。它负责回答四个治理问题:扩展是谁、由谁处理、是否必须执行、哪些字段属于它。

510 表示策略没有被满足

510 不是泛化的服务器故障。RFC 2774 第 7 节把它描述为资源访问策略未得到满足。响应应提供足够信息,让客户端知道怎样构造一份可接受的扩展请求。

如果响应列出了缺失扩展,而客户端有能力提供,就可以修改请求后重试;做不到时,响应体可作为面向用户或运维人员的诊断。一个只有 M- 方法却没有任何强制声明的请求同样要得到 510,因为它宣称“必须执行额外语义”,却拒绝说明额外语义是什么。

因此,510 处在一个很窄的位置:服务器可能在线,资源可能存在,基础方法可能也合法,但这次操作所要求的扩展合同没有成立。

成功也要有专门的回执

仅有错误码还不够。接收方真的完成强制扩展后,需要给出积极证据。Ext 表示所有端到端强制声明均已满足,C-Ext 则确认当前一跳的强制声明。两个字段不承载应用数据,只承担确认职责。

这种回执不是安全证明,也不能说明业务结果必然正确。它只解决一个更基础的问题:这份响应来自执行了扩展合同的路径,而不是来自一个只理解基础方法的旧路径。

代理与缓存把问题变成一张大矩阵

语义沿途有很多丢失机会。端到端声明要穿过并不理解它的代理;逐跳声明必须停在正确连接;旧代理可能不认识新的缓存控制;缓存还可能把依赖扩展生成的响应复用给没有相同声明的请求。

RFC 2774 因而规定,完成端到端强制请求的响应应带 Cache-Control: no-cache="Ext"。为照顾 HTTP/1.0 代理,还要加入一个已经过期的 Expires 时间。若响应随某个数字前缀字段变化,Vary 必须同时列出该字段和赋予它含义的声明字段。

这些细节不是装饰。每一条都堵住一次语义被剥离、错投或重放的机会。不过,它们也揭示了通用框架的成本:客户端、源站、代理、缓存以及不同 HTTP 版本必须共同理解一套交互规则。

实验结束,不等于问题消失

RFC 2774 的起点就带着保留意见。IESG 注释说明,文件原本申请 Proposed Standard,但 Last Call 与 HTTP 工作组内评价不一,社区对 HTTP 演进方向也未形成明确共识,因此改以 Experimental 发布。注释没有断言技术必然有缺陷,而是要求继续研究,并提醒人们不要把它当成所有 HTTP 扩展的蓝图。

2021 年,IETF 批准把 RFC 2774 与另外几项 HTTP 实验转为 Historic。官方理由很克制:实验已经结束,没有广泛使用的证据。IANA 现在把 510 记作 Not Extended (OBSOLETED),并把 Man、Opt、C-Man、C-Opt、Ext、C-Ext 全部标为 obsoleted。

这些记录不能证明从未有人部署,也没有给出采用有限的唯一原因。它们能确定的是:这套通用强制声明机制不再是现行 HTTP 工具。

HTTP 留下了更小的扩展面

HTTP 并未停止演进。RFC 9110 仍列出持久扩展点,包括方法、状态码、字段名、认证方案与缓存指令。它们通过明确的注册表和审查政策获得名称、语义与生命周期,而不是复活 RFC 2774 的通用声明矩阵。

被保留下来的教训比原方案更窄。扩展必须说明它是可选还是不可缺少,谁是最终解释者,如何避免命名冲突,经过中间设备时怎样保持作用域,以及失败与执行完成分别留下什么证据。

HTTP 510 已退出当代实践,但它命名的问题仍然存在:字节传到不等于双方理解一致。最危险的协议误解,往往正是那个返回成功的误解。

来源