在 RESTful SOA 中,假设我通过 AJAX 发出 POST 请求,但在请求超时之前没有收到响应。进一步假设重新提交请求将是有害的。 POST 不是幂等的。例如,也许我正在发布银行转账。如果我没有得到响应,我不知道服务器是否处理了请求。
假设我可以控制客户端和服务端,处理这个问题的最佳实践是什么?
我最初的想法是在每个 POST 请求中包含一个随机数(即伪 ID;某种唯一标识符);例如可能是 If-None-Match header 中的一个值。使用这种方法,客户端可以以编程方式重新发出具有相同伪 id 的超时请求,如果它包含重复值,服务器可以拒绝它。
最佳答案
我听说有很多方法可以尝试解决这个问题
设计服务,以便如果 POST 失败,客户端可以对同一资源发出 GET,并根据返回的数据确定 POST 是否成功。
这种方法的问题在于,在 POST 在集合中创建新项目的情况下,客户端可能难以确定发布是否成功(即,我的帖子添加了该项目还是其他人的?)
使用
If-Match
header 以防止重复 POST。例如,如果 POST 正在向集合中添加一个项目,并且该集合当前具有 ETag
的 737060cd8c284d8af7ad3082f209582d
.如 If-Match
的 737060cd8c284d8af7ad3082f209582d
用于 POST,则 POST 仅在集合的 ETag
时才会成功还在737060cd8c284d8af7ad3082f209582d
,这将添加项目并产生新的 ETag
为收藏。在这个阶段重复 POST 只会返回 412 Precondition Failed
.这种方法的问题在于当您收到
412 Precondition Failed
时,您无法确定您的 POST 是否修改了该集合或其他人的集合。 将您的服务设计为从不保留 POST 中的数据。相反,POST 使用 POST 内容创建一个临时资源,该资源处于“待处理”状态。然后使用 PUT“提交”这个临时资源。使用这种方法,您无需关心 POST 时间是否已过,只需再次请求 POST,这一次您有望获得临时资源。如果提交资源的 PUT 超时,您也不关心,因为 PUT 是幂等的。
这种方法唯一真正的缺点是管理临时资源所需的额外工作和客户端所需的额外工作。
更新
在请求中使用 nonce(即消息 ID、交易 ID、请求 ID、关联 ID)是解决此问题的常用方法;但是它可能存在可扩展性问题。
如果您 promise 拒绝所有使用先前随机数的 POST,则需要扫描现有的 POST 记录以确定之前是否使用过该随机数。当您只有几千个 POST 时这不是问题,但是当您有数百万个时可能会出现问题(特别是如果您没有以快速查询的方式存储随机数)。
您可以通过减少拒绝在特定时间范围内(例如,过去 24 小时)使用先前随机数的所有 POST 的 promise 来缓解这种情况,但是如果第一个 POST 超时并且客户端在该时间范围内断开连接,那么它们将返回相同的旧位置,他们不知道第一次 POST 是否成功,也无法确定是否应该重新发布。
关于rest - 如何处理超时的 POST 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13316357/