9

我最近发现,使用 Internet Explorer 运行我的应用程序的用户出现间歇性故障的问题是由于 Internet Explorer 中的错误造成的。该错误位于 HTTP 堆栈中,应该会影响所有使用来自 IE 的 POST 请求的应用程序。结果是失败的特征是请求似乎挂起大约 5 分钟(取决于服务器类型和配置),然后从服务器端失败。服务器放弃后,浏览器应用程序将在 post 请求中出错。我将在下面详细解释 IE 错误。

据我所知,任何使用 XMLHttpRequest 向服务器发送 POST 请求的应用程序都会发生这种情况,如果请求是在错误的时间发送的。我编写了一个示例程序,试图在这些时间发送 POSTS。它尝试在服务器关闭连接的精确时刻向服务器发送连续的 POST。间隔来自服务器发送的 Keep-Alive 标头。

我发现当从 IE 运行到具有一点延迟的服务器时(即不在同一个 LAN 上),问题仅在几次 POST 后出现。发生这种情况时,IE 会锁定得很厉害,以至于必须强制关闭。滴答作响的时钟表明浏览器仍在响应。

您可以通过浏览以下网址进行尝试: http: //pubdev.hitech.com/test.post.php请注意,当您运行它时,您在任何 IE 会话中都没有任何重要的未保存信息,因为我发现它会使 IE 崩溃。

完整的源代码可以在以下位置检索: http: //pubdev.hitech.com/test.post.php.txt。您可以在任何具有 php 并配置为持久连接的服务器上运行它。

我的问题是:

  1. 其他人在这个问题上的经验是什么?

  2. 是否有解决此问题的已知策略(“使用其他浏览器”除外)?

  3. Microsoft 是否有比我找到的文章更好的信息(见下文)?

问题是 Web 浏览器和服务器默认使用 RFC 2616 第 8.1 节中所述的持久连接(参见http://www.ietf.org/rfc/rfc2616.txt)。这对于性能非常重要——尤其是对于 AJAX 应用程序——并且不应该被禁用。然而,有一个小的时间漏洞,浏览器可能会在服务器决定连接空闲并决定关闭它的同时开始在先前使用的连接上发送 POST。结果是浏览器的 HTTP 堆栈将收到一个套接字错误,因为它正在使用一个关闭的套接字。RFC 2616 第 8.1.4 节预见了这种情况,并指出,“......客户端、服务器和代理必须能够从异步关闭事件中恢复。客户端软件应该重新打开传输连接并重新传输中止的请求序列而无需用户交互……”

发生这种情况时, Internet Explorer重新发送 POST,但它会破坏请求。它发送 POST 标头,包括发布的数据的 Content-Length,但它不发送数据。这是一个不正确的请求,服务器将等待一段未指定的时间来获取承诺的数据,然后再因错误导致请求失败。我已经能够使用模拟 HTTP 服务器的 C 程序在 100% 的情况下演示此失败,该服务器会关闭传入 POST 请求的套接字而不发送响应。

微软似乎在 http://support.microsoft.com/kb/895954中承认了这一失败。他们说它会影响 IE 版本 6 到 9。它为这个问题提供了一个修补程序,自 IE 7 以来的所有版本的 IE 都附带了该修补程序。由于以下原因,该修补程序似乎并不令人满意:

  1. 除非您使用 regedit 将名为 FEATURE_SKIP_POST_RETRY_ON_INTERNETWRITEFILE_KB895954 的键添加到注册表,否则它不会启用。这不是我希望我的用户必须做的事情。

  2. 该修补程序实际上并不能修复损坏的 POST。相反,如果套接字按照 RFC 的预期关闭,它会立即出错而不会尝试重新发送 POST。应用程序仍然失败——只是失败得更快。

以下示例是一个自包含的 php 程序,用于演示该错误。它尝试在服务器关闭连接的精确时刻向服务器发送连续的 POST。间隔来自服务器发送的 Keep-Alive 标头。

4

3 回答 3

6

我们经常在 IE 中遇到这个问题。没有好的解决办法。唯一能保证解决问题的办法是确保web服务器的keepalive超时时间高于浏览器的keepalive超时时间(IE默认是60s)。任何将 Web 服务器设置为较低值的情况都可能导致 IE 尝试重用连接并发送由于套接字已关闭而被 TCP RST 拒绝的请求。如果 web 服务器的 keepalive 超时值高于 IE 的 keepalive 超时值,则 IE 对连接的重用确保套接字不会关闭。对于高延迟连接,您必须考虑延迟时间,因为在传输中花费的时间可能是一个问题。

但是请记住,增加服务器上的 keepalive 意味着空闲连接使用服务器套接字的时间要长得多。因此,您可能需要调整服务器大小以处理大量不活动的空闲连接。这可能是一个问题,因为它可能会导致服务器无法处理的负载激增。

另一件事要记住。您注意到 RFC 部分 8.1.4 声明:“...客户端、服务器和代理必须能够从异步关闭事件中恢复。客户端软件应该重新打开传输连接并重新传输中止的请求序列而无需用户交互。. 。”

你忘记了一个非常重要的部分。全文如下: 只要请求序列是幂等的,客户端软件应该重新打开传输连接并重新传输中止的请求序列而无需用户交互(参见第 9.1.2 节)。非幂等方法或序列不得自动重试,尽管用户代理可以为人工操作员提供重试请求的选择。具有应用程序语义理解的用户代理软件的确认可以替代用户确认。如果第二个请求序列失败,则不应重复自动重试

HTTP POST 是 9.1.2 定义的非幂等的。因此,根据 RFC,注册表黑客的行为实际上在技术上是正确的。

于 2014-01-14T21:29:11.587 回答
0

不,通常 POST 在 IE 中工作。这可能是一个问题,你在说什么,但这不是一个大问题,值得发这么大的帖子。

当您发出 POST ajax 请求时,要确保涵盖所有浏览器不一致,只需使用 jquery。

还有一件事:没有人会告诉你“使用另一个浏览器”,因为 IE 被广泛使用并且需要得到照顾(嗯,除了 IE6 和某些,甚至可能是一些更新的版本)

所以,POST必须在 IE 中工作,但为了让自己免受意外错误行为的影响,使用 jquery 并且你可以睡得很好。

于 2012-11-15T01:52:32.407 回答
0

我从来没有遇到过这个问题。我们的客户大多运行 IE6。

我怀疑您将保持活动计时器配置的时间过长。大多数人将其配置为低于 1 秒,因为持久连接仅用于加速页面加载而不是服务 Ajax 调用。

如果您的 keep-alive 配置时间过长,您将面临比 IE 崩溃更严重的问题 - 您的服务器将用完文件描述符来打开套接字!*

* 注意:顺便说一下,打开和不关闭与 HTTP 服务器的连接是众所周知的 DOS 攻击,它试图强制服务器达到其最大打开套接字限制。这就是为什么大多数服务器管理员还配置连接超时以避免套接字打开时间过长。

于 2012-11-21T12:44:26.877 回答