2012-11-09 278 views
7

在RESTful SOA中,假设我通过AJAX发出POST请求,但在请求超时之前我没有收到响应。进一步假设重新提交请求会有害。 POST不是幂等的。例如,也许我正在发布银行转账。如果我没有得到回应,我不知道服务器是否处理了请求。如何处理超时POST请求

假设我可以控制客户端和服务端,最佳做法是什么?

我最初的想法是为包括随机数(即,伪ID;某种唯一标识符),每个POST请求;例如也许是If-None-Match标题中的一个值。通过这种方法,客户端可以通过编程方式重新发出具有相同伪ID的超时请求,并且服务器可以拒绝它,如果它包含重复值。

+1

如果您在某个超时后未收到响应,只是假设失败并要求客户端重试或中止。无论如何,服务器上的代码显然应该检查相同的ID。 – alfred

+0

要明确这一点,这个伪ID不是要*资源ID - 我不是直接寻址资源。我按照预期使用POST;即发布到资源处理程序(例如/传输,而不是/传输/ )。否则,我不会在第一时间做一个POST。 – johnr

+0

这与“[避免使用REST重复发布](http://stackoverflow.com/q/15159274/1347968)”类似。 – siegi

回答

4

有许多的方法,我听说过,试图解决这个

  1. 获取的当前状态。

    设计的服务,这样,如果POST失败,客户端可以发出对同一资源GET并根据返回的数据,就可以判断是否成功发布的不是。

    这种方法的问题在于POST在集合中创建新项目的情况下,客户可能难以确定该帖子是否成功(即,我的帖子添加了该项目还是做了别人的?)

  2. 的if-match

    使用If-Match头,以防止POST被重复。例如,如果POST正在将项目添加到集合中,并且集合当前具有ETag737060cd8c284d8af7ad3082f209582d。如果737060cd8c284d8af7ad3082f209582dIf-Match是在POST使用,那么POST将只在集合的ETag仍然737060cd8c284d8af7ad3082f209582d,这将增加该项目,并导致新的ETag的收集成功。在此阶段重复POST将仅返回412 Precondition Failed

    这种方法的问题是,当你得到一个412 Precondition Failed,你不能确定,如果你的后修饰的收集,还是别人的。

  3. POST然后把

    设计您的服务永远不会从POST留存数据。相反,POST会创建一个临时资源,POST内容处于“待定”状态。这个临时资源然后用PUT“提交”。通过这种方法,你不关心你的POST时间是否结束,只需要再次发布POST,这次你希望得到你的临时资源。如果PUT提交资源时间结束,你也不在乎,因为PUT是幂等的。

    这种方法的唯一真正的缺点是管理临时资源,并在客户端所需的额外工作所需的额外工作。

    更新

  4. 杜撰

    使用一个随机数(A.K.消息ID,事务ID,请求ID,相关ID)是解决此问题的常用方法;但它可能有可扩展性问题。 如果您承诺拒绝所有使用先前随机数的POST,则需要扫描现有POST记录以确定以前是否使用了随机数。当你只有几千个POST时,这并不是一个问题,但是当你拥有数百万个时(如果你没有以快速查询的方式存储这些随机数),它可能会出现问题。

    您可以通过减少拒绝在特定时间范围内(例如,最近24小时)内使用先前nonce的所有POST的承诺来减轻这一负担,但是如果第一次POST超时并且客户端在该时间段内断开连接,那么它们又回到了原来的位置,他们不知道第一次POST是否成功,也无法确定是否应该恢复。

+1

我提议的方式如何?你认为这是可行的吗? – johnr

+0

@johnr我已经更新了我的答案,覆盖了随机数 –

+1

+1。我个人更喜欢第三种选择;先创建资源然后使用PUT :) –