我理解HTTP请求会导致对代码和可选主体的响应。
如果我们将请求的发起者称为“客户”,请求的收件人是“服务器”。
然后序列是
服务器是否可以完成步骤3,但步骤4不会发生(由于连接断开,应用程序错误等原因)。
换句话说:服务器是否可能“相信”客户端应该收到响应,但客户端出于某种原因却没有?
答案 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 ,或者至少不像你从关系数据库那样期望的事务性。您需要从客户端添加另一个请求,也许您永远不会得到(因为服务器在收到确认之前已经崩溃)等等。