IE,XDomainRequest不总是工作 [英] IE, XDomainRequest not always work

查看:256
本文介绍了IE,XDomainRequest不总是工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在IE上做跨域。



我使用XDomainRequest和植入日志记录所有事件(onerror,onload,onprogress和ontimeout)



它有时工作,但不总是(一台计算机,IE9,同一网站,同一请求,3或4件作品中的1件;另一台电脑,IE8,也许是2个作品中的一个)。我没有从日志记录中获得任何有用的信息,因为没有触发任何东西。



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



感谢很多
coronin

解决方案

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();
}

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



你会注意到互联网上有很多其他讨论,提到在xdr.send()放置一个setTimeout;调用会以某种方式解决神秘的XDomainRequest失败。这是一个kludge,完全不正确。所有这一切发生的是,XDomainRequest对象被固定到setTimeout闭包,并不受快速垃圾收集。它不能解决问题。



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

  var pendingXDR = []; 

函数removeXDR(xdr){
// indexOf不总是被支持,你也可以使用jQuery.inArray()
var index = pendingXDR.indexOf(xdr);
if(index> = 0){
pendingXDR.splice(index,1);
}
}

函数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(){};
//注册其他事件处理程序

其他问题 p>

如果事件处理程序在调用.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


I am trying to do cross-domain on IE.

I used XDomainRequest, and implanted logging for all events (onerror, onload, onprogress and ontimeout) to monitor the progress.

It works sometime, but not always (one computer, IE9, same site, same request, 1 out of 3 or 4 works; another computer, IE8, maybe 1 out of 2 works). I didn't get any useful information from the logging, because there was nothing triggered.

I am very confused. Any debugging tool for IE? Why some time XDomainRequest just doesn't work?

Thanks a lot coronin

解决方案

There are at least two significant bugs in the XDomainRequest object, one that affects IE8 and another that affects IE9.

Issue 1 - Garbage Collection

In Internet Explorer 8, the XDomainRequest object is incorrectly subject to garbage collection after send() has been called but not yet completed. The symptoms of this bug are the Developer Tools' network trace showing "Aborted" for the requests and none of the error, timeout, or success event handlers being called.

Typical AJAX code looks a bit like this:

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

In this example, the variable containing XDomainRequest goes out of scope. If the user is unlucky, IE's Javascript garbage collector will run before send() asynchronously completes and the request will be aborted. Even though the XDomainRequest object can be captured into the OnLoad and OnError event handlers, IE will see that that entire object graph has no references to it and will garbage collect it. IE should be "pinning" the object until complete.

You'll notice quite a few other discussions on the internet mentioning that placing a setTimeout around the xdr.send(); call will somehow "solve" mysterious XDomainRequest failures. This is a kludge, and completely incorrect. All that's happening is that the XDomainRequest object is being "pinned" into the setTimeout closure and not subject to garbage collection as quickly. It doesn't solve the problem.

To correctly work around this issue, ensure the XDomainRequest is stored in a global variable until the request completes. For example:

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);
}

Issue 2 - Missing OnProgress EventHandler

This second issue is already known. Internet Explorer 9 introduced a regression in the XDomainRequest object where a missing (null) OnProgress event handler would cause the request to abort when it tries to report progress information.

For fast requests, IE9 never attempts to call the OnProgress event handler and the request succeeds. Certain conditions, such as when IE delays the request due to too many open connections, network latency, slow server responses, or large request or response payloads will cause IE9 to start to report progress information.

IE9 tries to call the event handler without first checking it exists, and the XDomainRequest object crashes and destroys itself internally.

To solve this issue, always ensure an event handler is attached to OnProgress. Given the bug, it's not a bad idea to defensively add event handlers to all of the object's events.

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

Other Issues

I've seem reports that XDomainRequest can fail if the event handlers are registered before .open() is called. Again, defensively, it's not a bad idea to register them between the .open() and .send() calls. I haven't personally verified whether it's an actual bug.

If you run into an "Access Denied" error, it's because XDomainRequest doesn't allow mismatched URI schemes between the target and host page. In other words, try don't call an HTTP resource from an HTTPS page.

Beware most of the XDomainRequest libraries on the internet. I looked at most of the popular ones, such as the various jQuery AJAX transport plugins (including the ones linked in another answer here).

And, of course, XDomainRequest is subject to all of it's normal limitations and constraints. These aren't bugs per-se, and compared with the alernatives (iframe kludges, Flash crossdomain.xml transports) they're not that bad.

I've posted a new jQuery AJAX XDomainRequest transport under a public domain license here: https://github.com/ebickle/snippets/tree/master/javascript/xdomainrequest

这篇关于IE,XDomainRequest不总是工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆