在使用POST创建新资源时,我一直在寻找防止意外创建重复资源的最佳实践,因为资源将由服务器命名,因此无法使用PUT。我正在构建的API将由移动客户端使用,我关注的情况是客户端在提交POST请求之后但在获得响应之前断开连接。我找到this question,但没有提到使用条件POST,因此我的问题。
对父资源进行条件POST,类似于使用条件PUT修改资源,这个问题的合理解决方案是什么?如果没有,为什么不呢?
客户端/服务器交互就像条件PUT一样:
客户端获取父资源,包括反映其当前状态的ETag(包括其下属资源),
客户端对父资源执行条件POST(包括If-Match标头中父级的ETag值)以创建新资源,
客户端在获取服务器响应之前断开连接,因此不知道它是否成功,
稍后,当重新连接时,客户端重新提交相同的条件POST请求,
先前的请求未到达服务器,因此服务器创建资源并回复201,或者先前的请求到达服务器,因此服务器回复412并且重复的资源是没创造。
答案 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从服务器获取此请求。
您的步骤将变为: -
使用PUT可能会更加安静,并让客户端决定资源名称。如果您不喜欢所选择的名称,则可以指示您已创建资源,但它的规范位置是服务器选择的位置。
答案 2 :(得分:0)
为什么不使用服务器选择使用的任何内部机制,根据实际资源在服务器上进行重复检测。
这样更安全。
然后将URL返回到适当的资源(无论是否是新创建的)。
如果父母ETag基于子资源的状态,那么它不是检查“重复资源”的可靠机制。所有你知道的是,自从上次以来,父母已经“改变”了。你怎么知道它是因为你的旧POST在断开后被处理了?可能是ETag的任何改变。
这基本上是一个乐观的锁定场景,它归结为另一个问题。如果资源已经创建,那么呢?这是一个错误吗?还是一个功能?你关心?当资源已经存在时,发送服务器默默忽略的创建请求是不是很糟糕?
如果它已经存在,但是“足够”(即说名称匹配但地址不同),那是不是重复?这是更新吗?尝试更改现有资源是错误的吗?
另一种解决方案是两次旅行。一个提出请求,另一个提交请求。如果请求被中断,您可以查询请求的状态。如果提交未通过,您可以再次提交。如果确实如此,那么你很高兴并且可以继续前进。
取决于您的通信的不稳定程度以及这项特定操作的重要性,无论您是想跳过篮球安全地进行操作。