IE,XDomainRequest并不总是有效

时间:2011-11-08 23:24:23

标签: javascript internet-explorer cross-domain xdomainrequest

我正在尝试在IE上进行跨域。

我使用了XDomainRequest,并为所有事件(onerror,onload,onprogress和ontimeout)植入了日志记录来监控进度。

它有时可以工作,但并非总是如此(一台计算机,IE9,相同的站点,相同的请求,3或4个工作中的1个;另一台计算机,IE8,可能是2个工作中的1个)。我没有从日志记录中获得任何有用的信息,因为没有触发任何信息。

我很困惑。 IE的任何调试工具?为什么有些时候XDomainRequest不起作用?

非常感谢 冠蛋白

2 个答案:

答案 0 :(得分:19)

XDomainRequest对象中至少存在两个重要错误,一个影响IE8,另一个影响IE9。

问题1 - 垃圾收集

在Internet Explorer 8中,调用send()但尚未完成后,XDomainRequest对象不正确地进行垃圾回收。这个bug的症状是开发人员工具'网络跟踪显示" Aborted"对于请求,并且不调用任何错误,超时或成功事件处理程序。

典型的AJAX代码看起来有点像这样:

function sendCrossDomainAjax(url, successCallback, errorCallback) {
  var xdr = new XDomainRequest();
  xdr.open("get", url);
  xdr.onload = function() { successCallback(); }
  xdr.onerror = function() { errorCallback(); }
  xdr.send();
}

在此示例中,包含XDomainRequest的变量超出范围。如果用户不幸,IE的垃圾收集器将在send()异步完成之前运行,请求将被中止。即使可以将XDomainRequest对象捕获到OnLoad和OnError事件处理程序中,IE也会看到整个对象图没有引用它并将垃圾收集它。 IE应该是"固定"对象直到完成。

您会注意到互联网上的其他一些讨论,提到在xdr.send()周围放置一个setTimeout;电话将以某种方式解决"解决"神秘的XDomainRequest失败。这是一个kludge,完全不正确。所有这一切都发生在XDomainRequest对象被固定"进入setTimeout闭包并且不受垃圾收集的影响很快。它没有解决问题。

要正确解决此问题,请确保XDomainRequest存储在全局变量中,直到请求完成。例如:

var pendingXDR = [];

function removeXDR(xdr) {
  // indexOf isn't always supported, you can also use jQuery.inArray()
  var index = pendingXDR.indexOf(xdr);
  if (index >= 0) {
    pendingXDR.splice(index, 1);
  }
}

function sendCrossDomainAjax(url, successCallback, errorCallback) {
  var xdr = new XDomainRequest();
  xdr.open("get", url);

  xdr.onload = function() {
    removeXDR(xdr);
    successCallback();
  }

  xdr.onerror = function() {
    removeXDR(xdr);
    errorCallback();
  }

  xdr.send();
  pendingXDR.push(xdr);
}

问题2 - 缺少OnProgress EventHandler

第二个问题已为人所知。 Internet Explorer 9在XDomainRequest对象中引入了回归,其中缺少(null)OnProgress事件处理程序会在请求尝试报告进度信息时导致请求中止。

对于快速请求,IE9从不尝试调用OnProgress事件处理程序并且请求成功。某些条件,例如由于过多的打开连接,网络延迟,服务器响应缓慢或大量请求或响应有效负载而导致IE延迟请求时,IE9将开始报告进度信息。

IE9尝试调用事件处理程序而不先检查它是否存在,并且XDomainRequest对象在内部崩溃并自行销毁。

要解决此问题,请始终确保将事件处理程序附加到OnProgress。鉴于该错误,在所有对象的事件中防御性地添加事件处理程序并不是一个坏主意。

var xdr = new XDomainRequest();
xdr.open("get", url);
xdr.onprogress = function() { };
// regsister other event handlers

其他问题

如果在调用.open()之前注册事件处理程序,我似乎有报告称XDomainRequest可能会失败。同样,在防守方面,在.open()和.send()调用之间注册它们并不是一个坏主意。我还没有亲自验证它是否是一个真正的错误。

如果遇到“拒绝访问”#34;错误,因为XDomainRequest不允许目标和主机页面之间的URI方案不匹配。换句话说,请尝试不要从HTTPS页面调用HTTP资源。

小心互联网上的大多数XDomainRequest库。我查看了大多数流行的插件,例如各种jQuery AJAX传输插件(包括在另一个答案中链接的插件)。

当然,XDomainRequest受其所有正常limitations and constraints的约束。这些不是本身的错误,并且与alernatives(iframe kludges,Flash crossdomain.xml传输)相比,它们 不好。

我在公共域名许可下发布了一个新的jQuery AJAX XDomainRequest传输:https://github.com/ebickle/snippets/tree/master/javascript/xdomainrequest

答案 1 :(得分:11)

有完全相同的问题。简短的解决方案:

  1. 使用以下代码:https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js
  2. 更新:链接已损坏,请在此处找到jaubourgs:https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

    1. 在xdr.js文件中添加xdr.onprogress = function() {};
    2. 详细信息可以在这里的jQuery主题讨论中找到

      http://bugs.jquery.com/ticket/8283

      其中最后一个回复包含xdr.onprogress修复,该修复源于此错误讨论,该讨论恰当地标题为

      “IE9 RTM - 如果未指定所有事件处理程序,XDomainRequest发出的请求可能会中止” http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/30ef3add-767c-4436-b8a9-f1ca19b4812e