表示的版本标记

HTTP实体标签通常写作ETag,是服务器为选定表示提供的不透明验证器,不是HTML标签或访问令牌。它使客户端能够询问已有副本是否仍可用,或要求修改仅针对自己读过的版本进行。现行HTTP语义标准RFC 9110与缓存标准RFC 9111均于2022年发布,分别列为互联网标准STD 97和STD 98。

标签值放在双引号内,例如“"rev7"”。客户端比较它,而不必理解内部构造;服务器可以用版本号、内容哈希或文件属性生成,规范没有指定唯一算法。同一资源不同表示需要恰当区分,但不同资源可以使用相同标签,因而它不是全站或全球唯一编号。

参考:[1] [2] [3]

强弱标签与两种比较

强验证器必须随表示数据中可观察的变化而改变。弱标签带有区分大小写的W/前缀,例如W/"rev7",可以把并非逐字节相同、但服务器认为足以互相替代的表示归为一组。弱并非加密强度低,而是所承诺的等价关系较宽。

强比较要求双方都不是弱标签,且不透明值相同;弱比较只比较不透明值。因此W/"rev7"与"rev7"可弱匹配,却不能强匹配。If-Match使用强比较,If-None-Match使用弱比较,不能为了让条件通过而任意删去W/。

参考:[1] [3]

以条件请求复用缓存

设浏览器已保存一份带ETag值"rev7"的网页。副本需要重新验证时,它发出GET请求并携带If-None-Match: "rev7"。若当前选定表示与之匹配,服务器返回304未修改响应,不重发正文;浏览器利用已有正文,并按响应信息更新适用的缓存头字段。如果不匹配且请求正常处理,则接收新的完整响应。

这不是省略所有网络通信,而是用一次较小的验证交换避免重复传输正文。缓存还必须按请求地址及Vary等规则选择合适副本,不能把任何同标签页面混用。ETag回答表示是否匹配;副本在多久以内无需重新验证,则由新鲜度规则处理,例如Cache-Control的max-age或Expires。具有ETag并不意味着永久新鲜。

参考:[2] [3]

避免更新相互覆盖

在编辑文档的例子中,甲、乙都读到版本"rev7"。乙先保存,服务器将当前标签改为"rev8"。甲随后用If-Match: "rev7"提交修改,条件失败时服务器不得执行该修改,通常返回412前置条件失败;甲可以重新读取并处理冲突。这种做法检测陈旧写入,并不自动合并两人的改动。

If-None-Match也不限于缓存:配合星号用于创建时,可要求目标当前没有表示,避免意外覆盖已有内容。标签条件不是身份认证,不能因为提交了正确ETag就获得写权限;服务器仍须先完成正常请求检查,再判断相应前置条件。

参考:[1] [3]