【问题标题】:REST optimistic-locking and multiple PUTsREST 乐观锁定和多个 PUT
【发布时间】:2016-02-22 12:28:29
【问题描述】:

据我了解,PUT 请求不应该返回任何内容。 考虑客户端想要运行这个伪代码:

x = resource.get({id: 1});
x.field1 = "some update";
resource.put(x);
x.field2 = "another update";
resource.put(x);

(假设我有一个输入控件和一个“保存”按钮,这允许我更改输入控件中显示的对象“x”的一部分,然后在按钮上单击 PUT 更改为服务器,然后继续编辑,也许“保存”对“x”的另一个更改)

根据关于如何在 REST API 中实现乐观锁定的不同建议,上述代码必须失败,因为 get() 返回的“x”的版本标记(无论如何实现)将在 put() 之后变得陈旧。 那么你们通常是如何让它发挥作用的呢? 还是在每次 PUT 后重新获取对象?

【问题讨论】:

  • 我想我可以从 PUT 返回一个更新的 ETag 响应标头,但我认为它在概念上与在响应正文中返回某些内容没有什么不同。 PUT 不应该返回任何东西,是吗?

标签: angularjs rest


【解决方案1】:

您可以对 HTTP 使用“条件”操作,例如此处描述的 If-Match 标头:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24

简而言之:您通过GET 请求传递ETag,并在If-Match 标头中将此ETag 提供回服务器。如果您尝试PUT 的资源有另一个ETag,服务器将响应失败。您还可以使用带有 If-Unmodified-Since 标头的简单时间戳。

当然,您必须让您的服务器代码理解条件请求。

对于多个步骤,PUT 确实可以返回新的表示,因此它也可以包含新的ETag 或时间戳。即使服务器没有返回 PUT 的新表示形式,您仍然可以将响应中的时间戳与 If-Unmodified-Since 条件 PUT 一起使用。

【讨论】:

  • 谢谢。所以基本上你的建议归结为“你必须从 PUT 返回一些东西才能使用多个 PUT,无论是更新的数据对象还是带有更新的 ETag 的标头”?还是我错过了什么?看起来这些与我在问题中描述的想法相同:)
  • 实际上让我烦恼的是 PUT 不应该返回任何东西的想法。看看stackoverflow.com/questions/797834/… - 或者,更确切地说,他们只是说“不需要响应正文”
  • “不需要响应正文”是正确的,规范并没有说你必须返回一些东西,它甚至有一个响应代码 (204 No Content) 来表明这一点。它没有说PUT 不应该返回任何东西。这实际上意味着如果对象的客户端视图发生更改,您应该这样做,我认为这正是您的用例。
【解决方案2】:

这可能就是我要找的东西:https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4 他们含蓄地说我们可以从 PUT 返回 ETag。尽管仅在案例服务器中应用了所提供的更改,但没有任何更正。

然而,这又引发了另一个问题。在现实世界中,应用程序 PUT 调用者将在 JS gui 中异步运行,就像我在问题中的示例一样。因此,无论是否输入任何更改,都可能会多次按下保存按钮。如果我们不使用乐观锁定,那么假定的 PUT 幂等性使得在每次单击按钮时发送另一个 PUT 查询是安全的,只要最后一个获胜(但实际上如果有更改则不能保证,所以问题仍然存在) .

但是对于乐观锁定,当第一次 PUT 成功时,它会返回更新的 ETag,好吗?如果还有另一个 PUT 请求正在运行,但标签版本仍然过时,则后一个请求将得到 412,并且用户将看到一条消息“其他人更改了资源” - 但实际上这是我们之前的更改。

您通常会做什么来防止这种情况发生?禁用“保存”按钮直到其请求完全完成?如果超时怎么办?或者您认为如果超时则看到并发更改错误消息是可以接受的,因为无论如何稳定性已经受到损害?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 2010-09-12
    • 2011-02-23
    • 2012-11-14
    • 1970-01-01
    相关资源
    最近更新 更多