ETag和集合

时间:2015-02-14 18:10:48

标签: rest http etag optimistic-locking

许多REST API提供搜索资源的功能。

例如,可以使用以下HTTP请求获取类型A的资源:

GET /A?prop1={value1}&prop2={value2}

我使用乐观锁定,因此希望为每个返回的A类资源返回一个版本。到目前为止,我在使用其ID仅获取一个资源时使用了ETag标头。

是否有HTTP方法可以在同一响应中为多个资源返回版本?如果没有,我应该在正文中包含版本吗?

谢谢, 迈克尔


编辑:我在网上发现ETag通常是通过计算部分回复的哈希来生成的。这种方法非常适合我的情况,因为将计算返回集合的哈希值。但是,如果客户端决定更新集合中的一个元素,那么他应该将哪个ETag置于If-Match标头中?我认为包含各个元素的ETag是唯一的解决方案......

2 个答案:

答案 0 :(得分:2)

我会采用以下选项之一:

  1. 默认情况下使ETag变弱,它们是使用资源当前状态生成的,而不是使用HTTP响应有效负载中的资源表示生成的。有了这个,我可以为集合查询响应体中的每个资源返回一个有效的ETag,除了响应头中整个集合的ETag。

  2. 忘记此案例的If-Match和ETag,并使用If-Unmodified-Since作为每个资源的属性提供Last-Modified。通过这样做,我可以保留强大的ETag,但客户端仍然可以根据集合响应对一个项目进行更新,而无需对资源本身提出另一个请求。

  3. 允许通过PATCH对集合资源本身进行更新,使用带有ETag的If-Match标头作为整个集合。如果有很多并发更改,这可能不会很好,但这是一种合理的方法。

答案 1 :(得分:2)

我认为这取决于减少带宽的资源,数据和请求的数量。但解决方案可能是分离子请求中的资源。

假设GET /images?car=mustang&viewangle=front的群组通话会返回5张图片。现在您可以将所有图像包含为二进制数据,并且GET请求本身具有唯一的ETag:

GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
ETag "aaaaaa"

data:image/png;base64,a123456....
data:image/png;base64,b123456....
data:image/png;base64,c123456....
data:image/png;base64,d123456....
data:image/png;base64,e123456....

现在的问题是,一个添加的图像会改变组呼的ETag,你需要再次传输完整的设置,而且只有一个图像发生了变化:

GET /images?car=mustang&viewangle=front
If-None-Match "aaaaaa"
...
HTTP 1.1 200 OK
ETag "bbbbbb"

data:image/png;base64,a123456....
data:image/png;base64,b123456....
data:image/png;base64,c123456....
data:image/png;base64,d123456....
data:image/png;base64,e123456....
data:image/png;base64,f123456....

在这种情况下,最好的解决方案是将资源数据与组呼叫分开。因此,响应仅包含子请求的信息:

GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
ETag "aaaaaa"

a.jpg
b.jpg
c.jpg
d.jpg
e.jpg

由此可以分别缓存每个子请求:

GET /image/?src=a.jpg
If-None-Match "Akj5odjr"
...
HTTP 1.1 304 Not Modified

<强>统计
- 第一次请求= 6x 200 OK
- 如果组未更改= 1x 304 Not Modified,则将来的请求 - 如果添加了一个新资源,则为未来请求= 2x 200 OK,5x 304 Not Modified

现在我将调整API文档。这意味着请求者必须在调用子请求之前检查子请求的缓存是否可用。这可以通过在组请求中提供ETag(或其他哈希)来完成:

GET /images?car=mustang&viewangle=front
...
HTTP 1.1 200 OK
...
ETag "aaaaaa"

a.jpg;AfewrKJD
b.jpg;Bgnweidk
c.jpg;Ckirewof
d.jpg;Dt34gsd0
e.jpg;Egk29dds
f.jpg;F498wdn4

现在请求者检查缓存并发现a.jpg有一个名为Akj5odjr的新ETag,而f.jpg;F498wdn4是一个新条目。到那时,未来的请求会减少:

<强>统计
- 第一次请求= 6x 200 OK
- 如果组未更改= 1x 304 Not Modified,则将来的请求 - 如果添加了一个新资源,则为未来请求= 2x 200 OK

<强>结论
最后,您需要考虑您的资源是否足够大以将它们放入子请求中以及一个请求者重复双组请求的频率(因此使用缓存)。如果没有,您应该将它们包含在组呼中,并且您没有优化空间。

P.S。您需要监视所有请求者以确保所有请求者都使用缓存。一种可能的解决方案是禁止请求者在不发送ETag的情况下调用API URL两次或更多次。