为什么Internet Explorer在Ajax调用失败后不发送HTTP POST主体?

115
我们能够可靠地重新创建以下场景:
  1. 创建一个小的HTML页面,使用HTTP POST向服务器发出AJAX请求
  2. 断开与网络的连接并重新连接
  3. 监视IE在故障后生成的数据包
在网络连接失败后,IE会进行下一次AJAX请求,但仅发送HTTP标题(而不是正文)时。这会在服务器上引起各种问题,因为它只是一个部分请求。通过使用Bing搜索此问题,你会发现许多人抱怨使用AJAX或未解释的AJAX故障导致“随机服务器错误”。
我们知道IE(与大多数其他浏览器不同)总是将HTTP POST作为两个TCP / IP数据包发送。标题和正文是分开发送的。在直接故障后的情况下,IE仅发送标题。 IE从不发送有效载荷,服务器最终以超时响应。
因此我的问题是 - 为什么它会以这种方式运行?根据HTTP规范和其他浏览器的行为,这似乎是错误的。这只是一个缺陷吗?毫无疑问,这会在任何严重的基于AJAX的Web应用程序中造成混乱。
参考信息:
存在类似的问题,由短于1分钟的HTTP保持活动超时引发,并在此处记录:

http://us.generation-nt.com/xmlhttprequest-post-sometimes-fails-when-server-using-keep-aliv-help-188813541.html

http://support.microsoft.com/default.aspx?kbid=831167


6
这是一个非常好的、清晰明了的问题,值得回答。不幸的是,这有些题外话。我不确定把它放在http://webmasters.stackexchange.com还是http://superuser.stackexchange.com上更好。 - Stephen
3
@gilly3,我想我的问题可能出在我自己身上,因为我读了那篇文章后就一直点头表示赞同... - Ryley
11
@gilly3:什么是Bing?我打算谷歌一下。 - gen_Eric
5
为什么它会表现出这种方式?你是否接受这样的回答:“微软的人们虽然大多数聪明,但他们所处的编程文化与我们这些通过DEC、Unix、Apple、Commodore或其他背景进入数字时代的人根本不同,他们倾向于做一些让我们惊叹的事情,不是因为他们的聪明才智,而是因为他们对对于我们来说简单明了的事物进行了过度复杂化和彻底的腐败”? - jcomeau_ictx
1
“缺失的帖子”条件只适用于重新连接后的POST,还是所有随后的POST都适用? - Ishmael
显示剩余7条评论
6个回答

28

对于这个问题似乎没有明确的答案,因此我将提供我的实证数据作为替代,并提供一些解决方法。也许某天微软内部人员能够解决这个问题...

  1. 如果服务器上禁用了 HTTP Keep-Alive ,这个问题就会消失。换句话说,你的 HTTP 1.1 服务器将在每个 Ajax 请求的响应中使用 Connection: Close 行来响应。这会让 IE 满意,但会导致每个 Ajax 请求都打开一个新连接。这可能会产生显著的性能影响,特别是在高延迟网络中。

  2. 如果 Ajax 请求快速连续地发出请求,就容易触发这个问题。例如,我们每100毫秒发起一次 Ajax 请求,然后网络状态发生变化,错误就容易重现。虽然大多数应用程序可能不会发出这样的请求,但您可能会有几个服务器调用紧随其后,这可能导致这个问题。较少的通信可以让 IE 满意。

  3. 即使没有 NTLM 认证,这个问题也会发生。

  4. 当服务器上的 HTTP keep-alive 超时时间小于默认值时(在 Windows 上默认为60秒),这个问题就会发生。有关详细信息,请参见问题中提供的链接。

  5. 在 Chrome 或 Firefox 中不会发生这个问题。Firefox 只发送一个数据包,似乎完全避免了这个问题。

  6. 这个问题发生在 IE 6、7、8 中。无法在 IE 9 测试版中重现。


4
有没有其他解决这个问题的方法?有没有JavaScript的解决方案?我尝试查看了各种XMLHTTP对象,但它们仍然无法解决这个问题。 - Berlin Brown

11

1
我在使用IE10时遇到了这个问题,而文章中并没有提到。 - ClearCloud8
6
这篇文章现在提到了IE11,因此看起来这个问题从未得到解决。 - peater
我相信我在一个生产网站上遇到了这个问题 - 与该问题相关的用户代理对应于IE 8,9,10和11。 - millhouse
有人找到解决方法吗?具体来说,我发送了一个307和FF,Chrome,Safari将数据重新发布到新的端点 - IE没有。我不能要求我的用户进行热修复/注册表修补。 - Brad Gunn

2
我曾经遇到过类似的问题,即一些旧版本的IE仅返回POST的Header而不是Body。我的问题最终与IE和NTLM有关。由于您没有提到NTLM,这可能对您没有帮助,但以防万一:

http://support.microsoft.com/kb/251404


你提供的链接对解决IE 11和IIS 6中类似的问题非常有帮助。 - Harminder

1

这可能有点冒险,但IE(甚至Firefox)有时会“记住”它用于HTTP请求的连接。注释/示例:

  • 在Firefox中,如果我更改代理设置并在页面上按SHIFT-RELOAD,它仍然使用旧代理。但是,如果我杀死旧代理(“killall squid”),它就开始使用新代理。

  • 当您断开/重新连接时,是否收到新的IP地址或类似的内容?您可以以某种方式监视旧IP地址,以查看IE是否向该已死地址发送数据吗?

  • 我猜测IE正在发送数据,只是走了错误的路径。它可能足够聪明,不会为“POST”数据包缓存网络连接,但可能不足以为POST有效负载执行此操作。

  • 这可能不会影响大多数AJAX应用程序,因为人们很少断开并重新连接到他们的网络?


2
我认为问题出在最后一个。我认为微软使用“很少发生:不实现”政策。 :) - user142019
1
我监控源到目的地的所有HTTP流量。我可以确认(a)我的IP地址没有改变,(b)也没有尝试发送其他任何内容。IE打开一个新的套接字并发送部分请求。根据我阅读的微软文章,他们的一个安全更新破坏了IE。然后他们创建了一个补丁来修复它。但是,如果您希望它以旧的“损坏”的方式运行,可以添加此注册表键Retry_HeaderOnlyPOST_OnConnectionReset。只是试图理解这种疯狂的情况。 - Dodgyrabbit
在你的最后一点上:如果您有一个定期轮询的Ajax应用程序,比如每10秒钟一次,我们发现如果保持打开几个小时,这个错误无论如何都会发生。可能是Wifi连接断开或网络不稳定 - 但我们的经验表明,这个问题是非常真实的。 - Dodgyrabbit

1
你是否正在使用NTLM身份验证?
当使用NTLM身份验证时,IE不会发送post-data。它发送头信息,期望未经授权的响应发送授权,并在“重新认证”之后发送post。

我们不使用NTLM认证。这种情况发生在匿名请求中。 - Dodgyrabbit

0
今天我在使用$.ajax时遇到了类似的问题,通过将async设置为false,我成功地解决了它。

$.ajax({
  async: false, 
  url: '[post action url]',
  data: $form.serialize(),
  type: 'POST',
  success: successCallback
});


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接