通过阅读answer上关于idempotency of HTTP PUT的问题,我了解到条件PUT请求的一个有趣方面,它导致了以下问题。
HTTP条件请求的规范在section 3.1中定义:
如果接收到原始服务器,则不得执行请求的方法 If-Match条件评估为false;而是原始服务器 必须使用以下任一方式响应:a)412(失败的前提条件)状态码 或b)2xx(成功)状态代码之一(如果原始服务器) 已经确认正在请求状态更改,并且最终 状态已经反映在目标的当前状态中 资源(即,用户代理请求的更改已经 成功,但是用户代理可能不知道它,也许 因为先前的响应丢失或进行了兼容的更改 由其他一些用户代理)。在后一种情况下,原始服务器 除非可以,否则不得在响应中发送验证者头字段 验证请求是否与之前的更改重复 由同一用户代理制作。
有条件的PUT请求用于避免多个代理在同一资源上并行操作(使用乐观锁定)时丢失更新的问题。 让我们假设资源的价值是
HTTP/1.1 200 OK
Content-Type: application/json
ETag: "0"
{ "value": 0 }
现在,两个客户端希望同时增加该值,并发送一个包含新值的正文的PUT
请求和一个If-Match
标头。
PUT /value HTTP/1.1
Content-Type: application/json
If-Match: "0“
{ "value": 1 }
服务器在状态为200
(OK
)的第一个请求上回答,而在状态为412
(Precondition Failed
)的第二个请求上回答,即第二个客户端必须重复他的任务(获取,更新资源,并使用带有新etag值的If-Match
标头将其放置)。
现在,我们假设两个客户端都没有收到答案,因此都再次发送了请求(显然,他们必须使用相同的If-Match
标头)。根据规范,服务器必须返回相同的状态码,即200
返回第一个,412
返回第二个。如果服务器将两者都返回200
,则更新将丢失,并且如果服务器将两者都返回412
,则两个客户端都将重新开始,并且最后的值将为3。 / p>
我的问题是这如何在服务器端实现。我认为服务器必须存储所有状态更改的历史记录以及客户端的标识。但是如何识别客户?将client-ip和User-Agent标头组合起来就足够了吗?
是否有(Java)库来实现此行为? 我也不清楚哪个验证者标头字段一定不能发送给客户端。