摘要
- 活跃的 No-Vary-Search 草案允许支持该扩展的缓存,在响应匹配时忽略指定的查询差异。它没有取代新鲜度、授权或内容协商,也没有证明客户端依据查询作出的决策同样等价。
- Chrome 文档明确区分准备地址与激活地址:预渲染页面最初看到自己的预渲染网址,等价导航激活它时再改成最终网址。依赖查询的状态必须在这个交接点建立或更新;地址栏变了,不代表旧数据模型、归因或行动目标已经一起改变。
设想一个商品目录。服务端为两件商品返回相同的初始 HTML,商品标识放在网址查询中,之后由客户端获取并呈现具体资料。读者还没有点击,浏览器就先准备了一张页面。预渲染期间,应用读取第一个标识,把它保存在模型里。读者最终点的是第二件商品。浏览器认为初始文档可以复用,于是激活已经准备好的页面,并把网址换成读者选择的地址。
网址已经正确,应用的选择也已经正确了吗?
初始 HTML 完全相同,并不能回答后一个问题。应用可能仍保留准备阶段的数据标识,某项测量可能仍归属于预期访问,下一次用户操作也可能指向旧模型。一个被捕获的变量,不会因为地址栏变化就自动成为当前状态。这是本文用于分析设计边界的假设场景,不是已发生的 Chrome 缺陷或客户事故。
No-Vary-Search 让这一区分具有实际意义。它可以说明某些查询差异不必触发另一份服务端响应,却不能说明准备期间依据旧查询形成的一切决策,在最终导航后仍然适用。把两者一起称为“同一页面”,相当于把一项缓存优化扩大成它无法提供的决策保证。
等价响应,不等于合并读者的选择
截至本文研究时点,draft-ietf-httpbis-no-vary-search-09 是 HTTPBIS 工作组这项活跃 Internet-Draft 的最新版本。2026 年 8 月的文本将在 2027 年 2 月 18 日到期。Datatracker 显示,它已经提交出版,处于“Approved-announcement to be sent::AD Followup”状态,目标 RFC 状态为 Proposed Standard。批准流程已经推进,不能把它描述成没有批准进展的个人建议;本文也没有把它当作已经出版的 RFC。
草案提出的响应字段使用 Structured Fields Dictionary。params 列表指定哪些参数的差异可以忽略;except 列表则保留列出的参数为重要差异,忽略其余参数。两项不能同时出现。key-order 处理参数名称顺序是否重要。已知字段采用无效形式时,解析退回默认变化配置,而不是悄悄变成“什么都可以忽略”。
这里增加的是响应匹配规则,不是从网址中抹掉信息。字段由源站设置;中间节点除非作为该响应的源站行事,否则不能自行插入、删除或修改。缓存还必须支持扩展,额外匹配规则才会生效。看到一个头字段,不等于已经证明所有浏览器、CDN 和前向代理都实现了它。
其他缓存条件继续存在。RFC 9111 规定的可缓存性与新鲜度并没有退出,内容协商和 Vary 也仍然参与判断。查询在 No-Vary-Search 下匹配,不代表一份个人响应可以交给另一个用户,更不代表可以无限期复用。源站所作的承诺,是特定查询差异不会改变所提供响应的语义,而这个承诺仍在其余 HTTP 缓存条件之内。
商品标识对共同的 HTML 外壳可能没有影响,对已经包含具体商品资料的服务端页面却可能至关重要。营销参数在某个应用中可能只供客户端使用,在另一个应用中却可能改变服务端返回内容。参数叫什么、被团队归入哪一类,都不能替代对真实响应的检查。“这只是追踪参数”不是一种跨应用通用证明。
预取响应,与预渲染运行中的页面不同
Chrome 官方文档说明了这个生命周期。No-Vary-Search 可以用于预取和预渲染导航推测。预渲染页面起初观察到的是用于准备它的网址。当读者最终点击一个只有被覆盖查询参数不同的网址时,Chrome 可以复用准备好的页面,在激活时把地址更新为最终地址。
文档因此提醒,依赖查询参数的 JavaScript 应在激活后执行;对于客户端渲染内容,还要注意在激活时更新。它的商品页例子恰好区分了两层:初始 HTML 相同,客户端后续获取的商品数据不同。这里使用的是 Chrome 文档记载的行为,不是对所有浏览器当前支持状况的概括。
测试时必须保留这些区别。预取是提前获取、准备响应;预渲染则可能准备一个在真正成为活动页面之前已经执行代码的页面。提前捕获旧标识的问题涉及后一种交接过程,不能说成任何预取都会执行页面脚本。普通导航、预取复用与预渲染激活,应当是不同测试人群和场景。
推测规则中的 expects_no_vary_search 也不是应用正确性的证明。它表达对响应字段的预期,可以帮助提前准备,但真正返回的源站合同仍需成立。预期字段、成功下载和成功激活,都没有自动证明模型或表单已经对应最终查询。
应用需要明确交接的含义:准备阶段依赖预计导航的状态,是暂定状态;激活时读取真实选择,再把相关状态和所有下游投影绑定过去。标题更新了,但行动目标仍是第一件商品,不算完成交接。数据重新获取了,但访问归因仍跟随旧查询,也不算完成交接。关键不是“某处读取过最终网址”,而是依赖这项选择的决策是否都取得了新的依据。
激活解决导航归属,不替代行动授权
真正有区分力的测试,是先按一个允许复用的查询准备页面,再用另一个等价查询激活它。接着同时检查当前对象、呈现内容和用户主动操作的目标。只看地址栏和可见标题,会遗漏仍藏在模型、闭包或测量上下文里的旧标识。网址正确与决策正确,是两件需要分别证实的事。
这并不要求所有工作都等到点击之后。共同外壳、共有资源以及真正独立于查询的准备,仍然可以提前完成。需要推迟或更新的是预计选择的权威地位。系统可以准备一种可能性,却不能因此认定读者已经选择了它,也不能让准备期间的猜测继续支配最终行动。
激活本身同样不是万能授权。它确定哪次导航已经成为实际导航,不能代替身份验证、访问权或对具体后果的同意。把操作绑定到正确标识,是不少决策的必要条件,但不是“可以对这个标识做任何事”的许可。读者进入页面,不等于要求应用对外披露资料或发出外部指令。
服务端也有不能交给客户端补救的边界。版本 09 明确要求,若忽略参数会绕过安全复用所必需的处理,源站就不能把它声明为 no-vary。草案列举授权、用户识别、签名验证、同意、路由、审计和撤销等情况。客户端在激活时更新得再准确,也救不了一份本来就不应共享、或绕过了必要服务端处理的响应。
共享缓存尤其需要区分两项控制。错误忽略选择个人或敏感内容的参数,可能把一个用户的响应交给另一个用户。源站响应等价保证控制“哪些内容能复用”,客户端激活交接控制“后续决策跟随谁的真实选择”。二者互补,不能互相充当替代品;页面很快,也不是二者都成立的证据。
查询比较不能靠字符串直觉
草案依据 application/x-www-form-urlencoded 解析与 WHATWG 约定比较查询,并不是让实现任意删掉若干子串。默认配置按查询本身精确比较。使用非默认配置后,才进入参数对解析、重要参数筛选以及按需要进行的名称稳定排序,随后逐项比较名称和值。
编码与重复值必须进入负向测试。加号、百分号编码以及无效 UTF-8 序列,会影响解析后的比较结果。允许忽略参数名称顺序,并不等于可以任意交换同一名称下的多个值。算法也不做 Unicode 规范化。草案特别提醒,有损解码可能让原本不同的查询变成同一结果;安全边界不应依赖无效编码在解析后仍然可区分。
这些细节不是要求管理层集中审批每个解析案例,而是要求最小合同把正确比较方法和重要负向测试说明白。团队可以根据本地响应选择参数意义,却不能把“两个网址看起来差不多”当作缓存采用的语义。灵活性应当留在决策对象上,不应留在未经定义的比较规则里。
新参数生效时,旧等价承诺未必已经消失
激活边界还有一个版本维度。今天对共同外壳无关紧要的参数,可能在下一次发布中影响服务端或客户端决策。except 只保留少量已知名称,同时也忽略尚未出现的新名称。较窄的 params 则让未列出的参数继续重要。二者没有跨应用通用的优劣结论,但它们把未来变化风险放在不同位置。
本文建议,在参数意义、服务端输出或客户端读取时点变化时,重新检查等价关系,并把承诺关联到发布版本和责任人。测试应把旧的存储响应放到新的导航语义下,而不只是检查新响应有没有新头字段。这是 Daniel Kade 的治理建议,不是 IETF 新规定的一组文章字段或客户端接口。
源站发出新字段,并不会回头改写所有缓存中的对象。草案让存储响应自己的变化配置参与匹配,也允许缓存采用偏向较新冲突策略的查找方式;它没有承诺旧等价策略在整个部署中立即撤回。同时,草案没有改变缓存失效要求:对概念上等价的 URI 扩大失效是允许的,但不是必须的。
所以,一次改变状态的请求未必已经让所有等价变体失效。为了“破缓存”而改变查询,也不总能取得新响应;如果相关存储策略忽略的正是那个参数,变化可能不起作用。迁移需要适合具体缓存和部署的验证、失效处理或独立资源命名空间,而不是假设每个新查询必然产生新工作。具体选择取决于缓存和部署条件,必须在仍可复用的旧响应上验证,而不能只看新策略已经发出。
旧响应与新客户端代码之间的过渡,也不能只靠一个总开关来描述。哪些对象仍携带旧策略,哪些导航会经过新的激活绑定,哪些用户状态不能复用,都需要可辨识的证据。允许缓存选择更少的候选,是性能上的自由,不是源站已经证明所有读者拿到同一新策略。发布完成与承诺退场之间,可能还有一段必须管理的时间。
把未来决策留在真正知道选择的地方
heng.lu 关于最小初始规范、未来决策本地化与自愿采用的论述,为这件事提供了一个清楚的尺度。好的小合同应说明哪些准备可以共享、哪项未来决定仍需在本地作出,而不是集中设计所有商品选择,或因为担心复杂性就取消一切推测性准备。
源站保留狭义的响应承诺,浏览器暴露明确的激活交接,应用在真实导航可知时建立或更新依赖查询的决策。这样,“同一页面”不再替三个不同责任主体背书。团队可以自愿采用优化,但采用的是一个有边界、可验证的合同,不是对全部层次的笼统信任。
隐私收益也需要这种分寸。草案说明,私有缓存复用可以避免源站对某些追踪标识的处理;共享缓存仍然收到带有这些标识的请求,字段也没有关闭客户端追踪。复用不等于匿名,激活不等于同意。能够长期成立的承诺更小:提前准备真正等价的响应,等读者作出真实选择后,再让决策取得真实依据。
来源
- Datatracker:No-Vary-Search 当前文档及出版状态。
- 草案版本历史。
- 版本 09 归档:比较、缓存与安全。
- 版本 09 纯文本。
- 版本 09 结构化源文件。
- HTTP Working Group 扩展文本。
- HTTP 扩展讨论记录。
- HTTPBIS 工作组说明。
- RFC 9110:HTTP 语义。
- RFC 9111:HTTP 缓存。
- RFC 9651:HTTP 结构化字段。
- RFC 6943:标识比较与安全。
- WHATWG URL 标准。
- WHATWG Infra 标准。
- Chrome:预渲染与 No-Vary-Search 激活提醒。
- heng.lu:最小规范、未来决策本地化与自愿采用。
- heng.lu:The Policy Mirror。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
