Jquery $.ajax 在跨域调用的 IE 中失败

Posted

技术标签:

【中文标题】Jquery $.ajax 在跨域调用的 IE 中失败【英文标题】:Jquery $.ajax fails in IE on cross domain calls 【发布时间】:2011-03-22 16:57:05 【问题描述】:

我正在使用$.ajax 进行跨域请求。它适用于 Firefox 和 Chrome,但不能在 IE 7 或 8 上发出调用。谁能告诉我以下有什么问题?

    我使用过 JSON 和 JSONP(由于一些自定义限制,我已停止使用)。 我已经在我的网站上使用Allow-access-control-origin 标头。 (没有这些,Chrome 和 Firefox 就无法发出成功的请求。) 我已经试过https://developer.mozilla.org/en/http_access_control

代码:

$.ajax(
    type: 'GET',
    url: "http://anotherdomain.com/Service/GetControl?id=" + zoneID,
    cache: false,
    contentType: "application/x-www-form-urlencoded",
    async: false,
    beforeSend: function (request) 
        //alert('before send');
        //request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        //request.setRequestHeader("X-PINGOTHER", "pingpong");
     ,
    success: function (data, status) 
        //alert("Data returned :" + data);
        //alert("Status :" + status);
        if (status == "success" && data != "")
            $("#" + div.id).append(data);
        else
            $("#" + div.id).attr("style", "display:none;");
    ,
    error: function (XMLHttpRequest, textStatus, errorThrown) 
        alert(textStatus);
        alert(errorThrown);
    
);

我尝试了多个网站上的各种提示,但还没有成功。

【问题讨论】:

相关:***.com/a/12014195/545328 【参考方案1】:

对于 IE8 和 IE9,您需要使用 XDomainRequest (XDR)。如果您看下面,您会发现它的格式与 $.ajax 类似。就我的研究而言,我无法让这个跨域在 IE6 和 7 中工作(仍在寻找解决方法)。 XDR 最早出现在 IE8 中(它也在 IE9 中)。所以基本上首先,我测试 6/7 并且不做 AJAX。

IE10+ 能够像所有其他浏览器一样正常跨域(恭喜微软...叹息)

之后 else if 测试窗口中的 'XDomainRequest(显然比浏览器嗅探更好)并以这种方式执行 JSON AJAX 请求,否则 ELSE 通常使用 $.ajax 执行它。

希望这会有所帮助!!我花了很长时间才弄清楚这一切

Information on the XDomainRequest object

// call with your url (with parameters) 
// 2nd param is your callback function (which will be passed the json DATA back)

crossDomainAjax('http://www.somecrossdomaincall.com/?blah=123', function (data) 
    // success logic
);

function crossDomainAjax (url, successCallback) 

    // IE8 & 9 only Cross domain JSON GET request
    if ('XDomainRequest' in window && window.XDomainRequest !== null) 

        var xdr = new XDomainRequest(); // Use Microsoft XDR
        xdr.open('get', url);
        xdr.onload = function () 
            var dom  = new ActiveXObject('Microsoft.XMLDOM'),
                JSON = $.parseJSON(xdr.responseText);

            dom.async = false;

            if (JSON == null || typeof (JSON) == 'undefined') 
                JSON = $.parseJSON(data.firstChild.textContent);
            

            successCallback(JSON); // internal function
        ;

        xdr.onerror = function() 
            _result = false;  
        ;

        xdr.send();
     

    // IE7 and lower can't do cross domain
    else if (navigator.userAgent.indexOf('MSIE') != -1 &&
             parseInt(navigator.userAgent.match(/MSIE ([\d.]+)/)[1], 10) < 8) 
       return false;
        

    // Do normal jQuery AJAX for everything else          
    else 
        $.ajax(
            url: url,
            cache: false,
            dataType: 'json',
            type: 'GET',
            async: false, // must be set to false
            success: function (data, success) 
                successCallback(data);
            
        );
    

【讨论】:

如果我能“标记为收藏”一个答案而不是问题:) 它工作得很好,但是我应该如何处理 IE8 和 IE9 中的 POST 请求 @Surya 看看这个例子:***.com/a/12233050/1492009。我很久以前就制作了这个函数,从那时起我让它变得更加通用/传入什么类型(get/post)。但你只是像往常一样传递它:xdr.open('POST', url); 通过客户端身份验证将不适用于 XDomainRequest。 (如果您正在寻找 xhrFields:withCredentials:true 的替代品)根据下面的帖子blogs.msdn.com/b/ieinternals/archive/2010/05/13/…,身份验证或 cookie 都不会传递 对于它的价值,似乎“data.firstChild.textContent”在 onload 函数的错误回退部分不是一个可行的值。我将其替换为“xdr.responseText.firstChild.textContent”......这应该会产生更一致的结果并实际通过 linting。【参考方案2】:

您能否检查一下 IE 的问题是否依赖于未定义安全区域以允许跨域请求? See this microsoft page 解释一下。

OTOH,this page 提到 IE7 和之前的版本不能进行跨域调用,但 IE8 可以使用与 XMLHttpRequest 不同的对象,JQuery 使用的对象。你能检查一下 XDomainRequest 是否有效吗?

编辑 (2013-08-22)

第二个链接已经失效,所以我在这里写下它的一些信息,取自wayback machine:

XDomainRequest 支持:IE8

IE 团队没有实现 XMLHttpRequest 的 CORS 版本,而是使用了自己的专有对象,名为 XDomainRequest。 XDomainRequest 的使用已从 XMLHttpRequest 简化,通过抛出更多事件(onload 可能是最重要的)。

这个实现有一些限制。例如,使用此对象时不会发送 cookie,这对于服务器端基于 cookie 的会话来说可能是一个令人头疼的问题。此外,无法设置 ContentType,这会在 ASP.NET 和其他服务器端语言中造成问题(请参阅http://www.actionmonitor.co.uk/NewsItem.aspx?id=5)。

var xdr = new XDomainRequest();
xdr.onload = function()  alert("READY"); ;
xdr.open("GET", "script.html");
xdr.send();

【讨论】:

感谢 luciano,我检查了 XDomainRequest 并在 IE8 上工作,但我必须编写单独的脚本来专门迎合 IE8。 是的,做的几乎一样,但是对于除 IE8 之外的所有浏览器都使用 $.ajax,$.ajax 在 IE6,IE7,FF3.5&Chrome 上工作,但是对于 IE8 编写了相同的 XdomainRequest代码。 今天我遇到了另一个解决我的问题的方法,因为在 IE 8 中,代码只需发送以下标题 Header Name = "p3p", VALUE = "CP=IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT" 举个例子吧。您是否将其添加到 beforeSend 函数中? @Furqan 设置 P3P 标头与允许跨域请求无关。该 response 标头涉及是否将给定的 cookie 设置或阻止为隐私风险。【参考方案3】:

jquery 为你做这件事,唯一的事情就是设置$.support.cors = true; 然后跨域请求在 jquery 用户的所有浏览器中都可以正常工作。

【讨论】:

如果你看一下这个问题被问到的日期,当时jquery还没有用来支持那个属性,它是后来引入的,但它仍然不能通过将它设置为来完成这个场景确实,您还需要调整一些服务器端设置。 需要发送哪些服务器头? $.support.cors = true; - 即使使用最新的 jquery,似乎也无法在 IE8 中工作。 这不适用于 IE 8 或 9。您仍然需要使用 XDomainRequest。仅设置 $.support.cors = true 是不够的。 在 IE8、jQuery 1.10.2 中没有影响 :(【参考方案4】:

只需安装这个 jQuery 插件:jQuery Cross-Domain AJAX for IE8

这个 1.4kb 的插件可以立即在 Internet Explorer 8 和 9 中运行。

在 jQuery 之后包含插件,并正常调用您的 ajax 请求。不需要其他任何东西。

Plugin GitHub repo and install instructions

【讨论】:

感谢您的帮助。您的回答可能对面临同样问题的人有所帮助。 在 jQuery 1.8.3 上的 IE7-9 中为我工作。这个插件非常难找。如果有人偶然发现这一点,请给这个答案它应得的支持。 请注意:github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest 不允许跨协议调用。【参考方案5】:

为 IE 的 jquery 添加额外的传输。 (只需将此代码添加到您的脚本中即可)

$.ajaxTransport("+*", function( options, originalOptions, jqXHR ) 

    if(jQuery.browser.msie && window.XDomainRequest) 

        var xdr;

        return 

            send: function( headers, completeCallback ) 

                // Use Microsoft XDR
                xdr = new XDomainRequest();

                xdr.open("get", options.url);

                xdr.onload = function() 

                    if(this.contentType.match(/\/xml/))

                        var dom = new ActiveXObject("Microsoft.XMLDOM");
                        dom.async = false;
                        dom.loadXML(this.responseText);
                        completeCallback(200, "success", [dom]);

                    else

                        completeCallback(200, "success", [this.responseText]);

                    

                ;

                xdr.ontimeout = function()
                    completeCallback(408, "error", ["The request timed out."]);
                ;

                xdr.onerror = function()
                    completeCallback(404, "error", ["The requested resource could not be found."]);
                ;

                xdr.send();
          ,
          abort: function() 
              if(xdr)xdr.abort();
          
        ;
      
    );

这解决了我的 Jquery $.ajax 跨域 AJAX 请求失败的问题。

干杯。

【讨论】:

2010年问这个问题时,jquery还不够成熟,你的解决方案可能已经解决了问题,但现在有点晚了。无论如何感谢您的帮助。【参考方案6】:

其他来到这里的人可能会很好地阅读http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx,其中谈到了 XDomainRequest 的限制

【讨论】:

【参考方案7】:

对于使用 jQuery 2.0 可能仍然存在此问题的任何人(我知道我有),Jay Dave 编写了最好的 jQuery 解决方法,但我仍有一些内容要添加到他的代码中,即:

确保您对请求使用相同的协议(HTTP -> HTTP 或 HTTPS -> HTTPS),Ayush Gupta 提供了一个知道问题的链接 使用 no-op 函数处理“onprogress”事件(这将防止 IE 在收到来自服务器的第一个位后中止请求。

完整代码如下:

// add ajax transport method for cross domain requests when using IE9
if('XDomainRequest' in window && window.XDomainRequest !== null) 
   $.ajaxTransport("+*", function( options, originalOptions, jqXHR ) 
       // verify if we need to do a cross domain request
       // if not return so we don't break same domain requests
       if (typeof options.crossDomain === 'undefined' || !options.crossDomain) 
           return;
       

        var xdr;

        return 
            send: function( headers, completeCallback ) 
                // Use Microsoft XDR
                xdr = new XDomainRequest();
                xdr.open("get", options.url); // NOTE: make sure protocols are the same otherwise this will fail silently
                xdr.onload = function() 
                    if(this.contentType.match(/\/xml/))
                        var dom = new ActiveXObject("Microsoft.XMLDOM");
                        dom.async = false;
                        dom.loadXML(this.responseText);
                        completeCallback(200, "success", [dom]);
                     else 
                        completeCallback(200, "success", [this.responseText]);
                    
                ;

                xdr.onprogress = function() ;

                xdr.ontimeout = function()
                    completeCallback(408, "error", ["The request timed out."]);
                ;

                xdr.onerror = function()
                    completeCallback(404, "error", ["The requested resource could not be found."]);
                ;

                xdr.send();
            ,
            abort: function() 
                if(xdr) xdr.abort();
            
        ;
    );

【讨论】:

在 jQuery 1.11.1 上对我不起作用,但由于 IE:没有合理的错误消息:'-( 原来的插件确实有效:github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js【参考方案8】:

注意,添加

$.support.cors = true;

足以强制 $.ajax 调用在 IE8 上工作

【讨论】:

感谢您的帮助。您的回答可能会帮助其他人搜索,对我来说已经太迟了,因为在提问时,jquery 没有对 IE8 的支持。 已经把这个属性设置为true了,在IE8还是不行。【参考方案9】:

只需添加“?callback=?” (或“&callback=?”)到您的网址:

$.getJSON(
    url:myUrl + "?callback=?",
    data: myData,
    success: function(data)
        /*My function stuff*/        
    
);

在进行调用时(如上所述为跨域正确设置了所有其他内容),这将触发正确的 JSONP 格式。

更深入的解释可以在答案here中找到。

【讨论】:

@Furqan 只是把它放在那里给遇到这个问题的人(比如我最近)。 为我工作...在地球上最繁忙的零售网站之一。你有小提琴或我们能看到的东西吗? 你误解了这个问题。这个问题围绕着 IE8 对跨域 AJAX 调用的支持,只能通过参考涉及 CORS 和 XDomainRequest 的解决方案来解决(a la github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest 为我解决了这个问题)。如果问题可以通过在 QueryString 上添加一个额外的参数来解决,你不认为你的答案会被接受吗?如果这真的是答案,你不认为这将是一个相当大的安全漏洞吗? 更好?没想到 8 个月后会出现这种情况......有些人显然发现它足够有用,可以投票。 @JamesMcCormack 添加了指向另一个答案的链接。试图克服这个问题,我发现这个答案是可行的,但它被很好地隐藏了。我将答案放在这里,以便其他有相同问题、搜索相同内容的人可以找到此信息。【参考方案10】:

@Furqan 请告诉我您是否使用 HTTP POST 方法对此进行了测试,

由于我也在处理同样的情况,但我无法将数据发布到不同的域。

但是在阅读this 之后,这很简单......唯一的事情是你必须忘记旧浏览器。我正在提供代码以从上述相同的 URL 使用 POST 方法发送以供快速参考

function createCORSRequest(method, url)
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr)
    xhr.open(method, url, true);
 else if (typeof XDomainRequest != "undefined")
    xhr = new XDomainRequest();
    xhr.open(method, url);
 else 
    xhr = null;

return xhr;


var request = createCORSRequest("POST", "http://www.sanshark.com/");
var content = "name=sandesh&lastname=daddi";
if (request)
    request.onload = function()
    //do something with request.responseText
   alert(request.responseText);
;

 request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            request.setRequestHeader("Content-length", content.length);
            request.send(content);

【讨论】:

这里的问题是旧浏览器,而不是发布请求。感谢您的帮助。【参考方案11】:

微软总是在弄巧成拙(至少在 IE 中):

http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

CORS 与 IE8 中的 XDomainRequest 一起使用。但是 IE 8 不支持 Preflighted 或 Credentialed Requests 而 Firefox 3.5+、Safari 4+ 和 Chrome 都支持此类请求。

【讨论】:

【参考方案12】:

我在IE中遇到同样的问题,我通过替换解决了:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

所以基本上升级你的 jquery 版本。

【讨论】:

【参考方案13】:

我在 IE9 中遇到了类似的问题,其中一些 CORS 调用正在中止,而另一些则没有。我的应用程序也依赖于一个 promise 接口,所以上面的 XDomainRequest 建议并不是我所需要的,所以我在我的 service.get IE9 解决方法中添加了一个 deferred。希望它对遇到此问题的其他人有用。 :

    get: function (url) 
        if ('XDomainRequest' in window && window.XDomainRequest !== null) 
            var deferred = $.Deferred();
            var xdr      = new XDomainRequest();

            xdr.open("get", url);

            xdr.onload = function() 
              json = xdr.responseText;
              parsed_json = $.parseJSON(json);
              deferred.resolve(parsed_json);
            

            xdr.send();
            return deferred;
         else 
            return $.ajax(
                url: url,
                type: 'GET',
                dataType: 'json',
                crossDomain: true
            );
        
    

【讨论】:

【参考方案14】:

由于问题中缺少格式,很难说,但我认为我发现 ajax 调用存在两个问题。

1) contentType 的 application/x-www-form-urlencoded 应该用引号引起来

2) contentType 和 async 参数之间应该用逗号分隔。

【讨论】:

您好,Kall,感谢您的回复。我也试过你的建议,有问题是打错了。它在 Chrome 和 Firefox 中运行良好,适用于预检请求,但在 IE 中无法运行。却又说不清为什么?如果您有任何提示,请与我分享。

以上是关于Jquery $.ajax 在跨域调用的 IE 中失败的主要内容,如果未能解决你的问题,请参考以下文章

我们可以在跨域中使用 Jquery $.ajax() 调用通过 https 访问 WCF 服务吗?

在跨域请求中捕获 JSONP 错误

当dataType为JSONP时没有调用ajax成功回调函数。在跨域访问中

iframe子页面在跨域情况下使用父页面的方法

JQuery - $.ajax() - 使用 JSONP 的跨域 - 仅在 IE 8 中获取“解析器错误”(在 IE 7 中工作)

在跨域ajax post中的回调函数中获取未定义