REST:通过条件POST阻止创建重复资源?

时间:2013-04-09 20:20:23

标签: rest post

在使用POST创建新资源时,我一直在寻找防止意外创建重复资源的最佳实践,因为资源将由服务器命名,因此无法使用PUT。我正在构建的API将由移动客户端使用,我关注的情况是客户端在提交POST请求之后但在获得响应之前断开连接。我找到this question,但没有提到使用条件POST,因此我的问题。

对父资源进行条件POST,类似于使用条件PUT修改资源,这个问题的合理解决方案是什么?如果没有,为什么不呢?

客户端/服务器交互就像条件PUT一样:

  1. 客户端获取父资源,包括反映其当前状态的ETag(包括其下属资源),

  2. 客户端对父资源执行条件POST(包括If-Match标头中父级的ETag值)以创建新资源,

  3. 客户端在获取服务器响应之前断开连接,因此不知道它是否成功,

  4. 稍后,当重新连接时,客户端重新提交相同的条件POST请求,

  5. 先前的请求未到达服务器,因此服务器创建资源并回复201,或者先前的请求到达服务器,因此服务器回复412并且重复的资源是没创造。

3 个答案:

答案 0 :(得分:1)

你的解决方案很聪明,但不太理想。您的客户可能永远不会得到他的201确认,并且必须将412错误解释为成功。

REST afficianados经常建议您使用空POST创建资源,然后,一旦客户端具有新创建的资源的id,他就可以执行"幂等"更新以填充它。这很不错,但是您可能需要使DB列可以为空,否则就不会这样,如果没有其他人同时尝试更新,那么您的更新只是幂等的。

根据ME,HTTP是不稳定的。请求超时,浏览器窗口关闭,连接重置,火车进入隧道与移动用户登机。有一个简单,强大的模式来处理这个问题。应始终唯一地标识不安全的操作,并且服务器应存储并且必要时能够重复对任何不安全请求的响应。这不是HTTP缓存,其中可以从缓存提供请求,但是可以出于任何原因刷新缓存。这是服务器应用程序的保证,如果" action"请求被第二次看到,存储的响应将重复而不会发生任何其他事情。如果要由服务器生成动作标识,那么请求响应应专用于发送id。如果你为一个不安全的请求实现这个,你也可以为所有这些请求做到这一点,这样你就可以解决许多棘手的问题:连续的更新请求会消灭其他用户'更改或命中不兼容的状态("已提交的订单"),连续删除请求生成404错误。

我有一些谷歌文档更全面地探索模式if you're interested

答案 1 :(得分:0)

我认为这个计划会起作用。如果您想确保POST不会导致重复,您需要客户端在POST中发送一些独特的内容。然后,服务器可以验证唯一性。

您也可以让客户端为每个请求生成GUID,而不是通过GET从服务器获取此请求。

您的步骤将变为: -

  1. 客户端生成GUID
  2. 客户端对资源执行POST,其中包括GUID
  3. 客户端断开连接并且不知道它是否成功
  4. 客户端再次连接并使用相同的GUID执行另一个POST
  5. 服务器检查GUID,并创建资源(如果它从未收到第一个POST)或指示这是重复的
  6. 使用PUT可能会更加安静,并让客户端决定资源名称。如果您不喜欢所选择的名称,则可以指示您已创建资源,但它的规范位置是服务器选择的位置。

答案 2 :(得分:0)

为什么不使用服务器选择使用的任何内部机制,根据实际资源在服务器上进行重复检测。

这样更安全。

然后将URL返回到适当的资源(无论是否是新创建的)。

如果父母ETag基于子资源的状态,那么它不是检查“重复资源”的可靠机制。所有你知道的是,自从上次以来,父母已经“改变”了。你怎么知道它是因为你的旧POST在断开后被处理了?可能是ETag的任何改变。

这基本上是一个乐观的锁定场景,它归结为另一个问题。如果资源已经创建,那么呢?这是一个错误吗?还是一个功能?你关心?当资源已经存在时,发送服务器默默忽略的创建请求是不是很糟糕?

如果它已经存在,但是“足够”(即说名称匹配但地址不同),那是不是重复?这是更新吗?尝试更改现有资源是错误的吗?

另一种解决方案是两次旅行。一个提出请求,另一个提交请求。如果请求被中断,您可以查询请求的状态。如果提交未通过,您可以再次提交。如果确实如此,那么你很高兴并且可以继续前进。

取决于您的通信的不稳定程度以及这项特定操作的重要性,无论您是想跳过篮球安全地进行操作。