是HTTP请求'原子'

时间:2016-10-20 09:49:36

标签: http

我理解HTTP请求会导致对代码和可选主体的响应。

如果我们将请求的发起者称为“客户”,请求的收件人是“服务器”。

然后序列是

  1. 客户端发送请求
  2. 服务器接收请求
  3. 服务器发送响应
  4. 客户收到回复
  5. 服务器是否可以完成步骤3,但步骤4不会发生(由于连接断开,应用程序错误等原因)。

    换句话说:服务器是否可能“相信”客户端应该收到响应,但客户端出于某种原因却没有?

2 个答案:

答案 0 :(得分:3)

网络本质上是不可靠的。如果对方已经确认了消息,您只能确定消息已到达,但您永远不会知道消息已到达。

更糟糕的是,对于HTTP,对请求的唯一确认是答案,并且没有答复的确认。这意味着:

  • 客户端知道服务器在收到响应后处理了请求。如果没有,则不知道请求是否已处理
  • 服务器永远不知道客户端是否得到了答案

TCP堆栈通常会在关闭套接字时确认答案,但该信息不会传播到应用程序层,并且在那里没有用,因为堆栈可以确认收到,然后应用程序可能无法处理消息因为它崩溃(或电源故障或某事)并且从应用程序的角度来看,无论原因是在TCP堆栈中还是在它之上 - 无论是否处理消息都无关紧要。

处理此问题的最简单方法是使用幂等操作。如果服务器再次获得相同的请求,则它没有副作用且响应相同。这样,客户端,如果超时等待响应,只需再次发送请求,最终(除非连接被撕掉,永远不再修复)得到响应,请求将完成。

如果所有其他方法都失败了,您需要记录已执行的请求并消除服务器中的重复项。因为没有网络协议可以为您做到这一点。它可以消除许多(如TCP所做的),但不是全部。

答案 1 :(得分:0)

HTTP RFC7230 6.6 Teardown上有一个关于该点的特定部分(粗体添加):

  

(...)

     

如果服务器立即关闭TCP连接,则有   客户无法阅读最后一个的重大风险   HTTP响应

     

(...)

     

为避免TCP重置问题,服务器通常会关闭连接   分阶段。首先,服务器仅通过关闭执行半关闭   读/写连接的写侧。服务器然后   继续从连接读取,直到它收到一个   客户端对应关闭,或直到服务器合理   确定它自己的TCP堆栈已收到客户端的   确认包含服务器最后一个的数据包   响应。最后,服务器完全关闭连接。

是的,这个响应发送步骤是一个非常复杂的东西。

例如,检查此Apache 2.4 document或复杂FIN_WAIT/FIN_WAIT2 pages for Apache 2.0上的延迟关闭部分。

所以,一个好的HTTP服务器应该保持套接字足够长,以便合理地确定在客户端就可以了。但是,如果您确实需要在Web应用程序中确认某些内容,则应使用回调(图像回调,ajax回调)断言响应已在客户端浏览器中完全加载(因此另一个HTTP请求)。这意味着它不像你说的那样是 atomic ,或者至少不像你从关系数据库那样期望的事务性。您需要从客户端添加另一个请求,也许您永远不会得到(因为服务器在收到确认之前已经崩溃)等等。