IE,XDomainRequest并不总是有效

cor*_*nin 11 javascript internet-explorer cross-domain xdomainrequest

我想在IE上做跨域.

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

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

我很迷茫.IE的任何调试工具?为什么有些时候XDomainRequest不起作用?

非常感谢coronin

Sha*_*ser 19

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

问题1 - 垃圾收集

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

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

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

在此示例中,包含XDomainRequest的变量超出范围.如果用户不幸,IE的Javascript垃圾收集器将在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);
}
Run Code Online (Sandbox Code Playgroud)

问题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
Run Code Online (Sandbox Code Playgroud)

其他问题

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

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

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

当然,XDomainRequest受其所有常规限制和约束的约束.这些不是bug本身,与alernatives(iframe kludges,Flash crossdomain.xml传输)相比,它们并没有那么糟糕.

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


Mar*_*ool 11

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

  1. 使用此代码:https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js

更新:链接已损坏,请在此处找到jaubourgs:https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

  1. 添加xdr.onprogress = function() {};该xdr.js文件

有关详细信息,请参阅此处的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