在任何地方,您都会看到人们建议将etag
标头与if-match
结合使用,以便在REST API中进行资源版本控制。
从阅读RFC来看,这实际上是错误的。
Etags特定于表示,这意味着完全相同数据的XML和JSON版本将具有不同的etags。更重要的是,gzip压缩版本会有不同的标签。
除此之外,etag是根据传输的实际字节生成的,因此根据RFC使用数据库version
字段实际上是错误的。
基本上是因为etags是为缓存目的而设计的,而不是为并发更新而设计的。
那么,考虑到这一点,在REST API中处理对RFC正确的并发更新的“正确”方法是什么?
答案 0 :(得分:0)
您要查看的规范是RFC 7234,它描述了如何在HTTP 1.1中处理条件请求(截至2014年6月)。
特别是,该规范描述了强弱验证器。
强验证器可用于所有条件请求,包括缓存验证,部分内容范围和"丢失更新"回避。弱验证器仅在客户端不需要与先前获得的表示数据完全相等时使用,例如在验证缓存条目或限制Web遍历到最近的更改时。
实体标签有强烈和弱的味道。
entity-tag是一个不透明的验证器,用于区分同一资源的多个表示,无论这些多个表示是由于资源状态随时间的变化,内容协商导致多个表示同时有效,或者两者。
规范进一步定义了strong comparison在MUST比较实体标签时使用的If-Match,这是一个强烈的实体标签是"正确& #34;处理条件请求的方式(include state changing requests)。
除此之外,etag是根据传输的实际字节生成的,因此根据RFC使用数据库版本字段实际上是错误的。
我在RFC 7234中找不到任何支持此声明的证据; section 2.3.3中的示例表明该声明是错误的。
它给出了完全相同资源的表示 - 一个是GZip而一个没有 - 每个都有不同的ETag。
那是对的 - 因为表示不同,ETag也必须不同。
但是,您并不需要使用实际字节来生成实体标记。允许与表示一对一的任何标签映射。
所以你可以拥有{database.version}.json
,{database.version}.xml
,{database.version}.xml.gz
- 这些都是标识相同"版本"的不同表示的标签。资源。
详情见section 2.3.1:Generation
例如,具有应用于所有更改的特定于实现的版本控制的资源可能使用内部修订号,可能与内容协商的方差标识符结合使用,以准确区分表示。
示例:底层域模型位于版本10.我正在使用JSON,因此我获得了资源的副本并开始操作我的副本
GET /X
200 OK
ETag: 10.json
同时,您也有兴趣进行更改,但由于不同的原因,您正在使用不同的表示
GET /X
200 OK
ETag: 10.xml.gz
现在我们都尝试将更改发布到服务器,在两个请求之间引入数据竞争
PUT /X
If-Match 10.json
PUT /X
If-Match 10.xml.gz
服务器可以选择如何支持这些请求;最有可能是通过序列化处理程序或使用一些乐观的并发机制。服务器可以看到实体标签存在,并从不透明标签中提取所需的数据。比赛的获胜者获得成功消息(可能使用映射到新表示的新实体标签),比赛的输家获得具有412 Precondition Failed
语义的响应。