Jquery在跨域调用时在IE中失败的问题

64

我正在使用$.ajax进行跨域请求。在Firefox和Chrome上可以工作,但在IE 7或8上不会发出调用。有人能告诉我以下代码有什么问题吗?

  1. 我已经尝试使用JSON和JSONP(由于一些自定义限制,我停止了使用JSONP)。
  2. 我已经在我的网站上使用了Allow-access-control-origin头部。(没有这些头部,Chrome和Firefox无法进行成功的请求。)
  3. 我已经尝试过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);
    }
});

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


相关:http://stackoverflow.com/a/12014195/545328 - 65Fbef05
14个回答

63
对于IE8和IE9,您需要使用XDomainRequest(XDR)。如果您往下看,您会发现它的格式与$.ajax类似。据我的研究,我无法在IE6和7中实现跨域(仍在寻找解决方法)。 XDR首次出现在IE8中(它也在IE9中)。因此,首先,我测试6/7并不使用AJAX。

IE10+能够像其他浏览器一样正常进行跨域操作(恭喜Microsoft...叹气)

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

希望这有所帮助!我最初花了很长时间才弄清楚所有这些

关于XDomainRequest对象的信息

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

2
如果我能够将答案标记为“收藏”,而不是问题本身,那该多好啊 :) - Vikram Deshmukh
1
它运行得非常完美,但是对于IE8和IE9中的POST请求我该怎么办? - Surya
@Surya 看看这个例子:https://dev59.com/MmfWa4cB1Zd3GeqPg3Dw#12233050。我很久以前就写了这个函数,从那时起,我已经让它变得更加通用/传递什么类型(get/post)。但你只需要像平常一样传递它:`xdr.open('POST', url);` - Mark Pieszak - Trilon.io
传递客户端身份验证将无法使用XDomainRequest。(如果您正在寻找xhrFields:{withCredentials:true}的替代品) 根据下面的文章,身份验证或cookie都不会被传递。 http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx - Dan
就其价值而言,在 onload 函数的错误回退部分中似乎“data.firstChild.textContent”不是可行的值。我用“xdr.responseText.firstChild.textContent”替换它……那应该产生更一致的结果并通过语法检查。 - Crates

32
你能否检查一下IE的问题是否与未定义安全区域以允许跨域请求有关? 请参阅此Microsoft页面进行说明。另外,这个页面提到,IE7及更早版本无法进行跨域请求,但是IE8可以使用不同于XMLHttpRequest的对象(JQuery使用的对象)进行请求。你能否检查XDomainRequest是否有效?编辑(2013-08-22)第二个链接已经失效,所以我会在这里写一些从Web存档机器中获取的信息:XDomainRequest支持:IE8。与实现CORS版本的XMLHttpRequest不同,IE团队采用了自己的专有对象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();

1
是的,几乎做了同样的事情,但对于除IE8之外的所有浏览器都使用$.ajax,$.ajax在IE6、IE7、FF3.5和Chrome上工作正常,但对于IE8编写了相同的XdomainRequest代码。 - Furqan Hameedi
1
今天我找到了另一个解决方案来解决我的问题,因为在IE 8中,只需发送以下标头代码即可正常工作:标头名称 =“p3p”, 值=“CP=IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT” - Furqan Hameedi
IE需要比其他浏览器更多的手把手指导才能使CORS正常工作。我曾经遇到过同样的问题,但通过http://forum.jquery.com/topic/cross-domain-ajax-and-ie解决了它,其中有一段代码可以解决这个问题。 - daveagp
2
@Furqan 设置P3P头与允许跨域请求无关。该响应头部涉及特定cookie是否会被设置或阻止作为隐私风险。 - EricLaw
第二个链接 (actionmonitor.co.uk) 已经失效。 - ashack
显示剩余3条评论

23

Jquery可以为您完成这项操作,您只需设置$.support.cors = true; 然后跨域请求就可以在所有浏览器中正常工作。


6
如果你看一下这个问题被提出的日期,当时jquery并不支持那个属性,它是后来引入的,即使将其设置为true也不能完成场景,你还需要调整服务器端的设置。 - Furqan Hameedi
需要发送哪些服务器头? - Michael Yagudaev
12
即使使用最新的jQuery至今,$.support.cors = true; 在IE8中似乎仍然无法工作。 - Tito
11
对于IE 8或9不适用。你仍然需要使用XDomainRequest。仅仅设置$.support.cors = true是不够的。 - d512
1
在IE8和jQuery 1.10.2中没有影响 :( - Ain Tohvri
这个解决方案适用于我在启用IE8标准模式的IE9中使用jQuery 1.11.0。 - Greg Prisament

20

谢谢你的帮助之手,亲爱的。你的答案可能会帮助到遇到同样问题的人。 - Furqan Hameedi
5
这个插件在IE7-9和jQuery 1.8.3上对我很有效。这个插件非常难找到。如果有人偶然发现了这个问题,请给这个答案点赞。 - Anthony DiSanti
请注意:https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest 不允许跨协议调用。 - Jason D.

7
在jquery中为IE添加额外的传输方式。 (只需在脚本末尾添加此代码)
$.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跨域请求失败的问题。
谢谢。

当这个问题在2010年被提出时,jQuery还不够成熟,你的解决方案可能已经解决了问题,但现在有点晚了。无论如何,感谢你的帮助之手。 - Furqan Hameedi

5

3

对于任何仍然使用jQuery 2.0的人(我知道我是),Jay Dave编写了最佳的jQuery解决方法,但我仍然有一些东西要添加到他的代码中,即:

  • 确保您对请求使用相同的协议(HTTP-> HTTP或HTTPS-> HTTPS),Ayush Gupta提供了一个已知问题的链接。
  • 使用无操作函数处理“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:没有合理的错误消息:'-( 然而,原始插件确实有效:https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js - Simon Steinberger

2
只需将"?callback=?"(或"&callback=?")添加到您的URL中:
$.getJSON({
    url:myUrl + "?callback=?",
    data: myData,
    success: function(data){
        /*My function stuff*/        
    }
});

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

更深入的解释可以在这里找到。


1
@Furqan 只是为了让任何遇到这个问题的人(比如我最近自己)知道。 - Randy Hall
在地球上最繁忙的零售网站之一,这对我很有效。你有什么代码或者演示可以分享吗? - Randy Hall
1
你误解了问题。这个问题围绕着IE8对跨域AJAX调用的支持,只能通过参考涉及CORS和XDomainRequest的解决方案来解决(例如https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest,这为我解决了问题)。如果问题可以通过在QueryString上添加额外的参数来解决,你不认为你的答案会被接受吗?而且,如果那真的是答案,你不认为这将是一个相当大的安全漏洞吗? - James McCormack
更好了吗?没想到8个月后还会出现这个...一些人显然发现它足够有用,以至于给它点赞。 - Randy Hall
@JamesMcCormack添加了另一个答案的链接。在尝试解决问题时,我发现那个答案可以解决问题,但是它被隐藏得很好。我把答案放在这里,以便其他遇到同样问题并搜索相同内容的人可以找到这些信息。 - Randy Hall

2
注意,添加

标签将会结束当前段落。
$.support.cors = true;

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

感谢您的帮助。您的答案可能会帮助其他正在寻找答案的人,但对我来说已经太晚了,因为在提问时,jQuery还没有为IE8提供支持。 - Furqan Hameedi
已将此属性设置为true,但在IE8中仍无法正常工作。 - SikoSoft

1
@Furqan,你能否告诉我你是否使用HTTP POST方法进行了测试?
因为我也在处理同样的情况,但我无法将数据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);
}

这里的问题是旧浏览器,而不是POST请求。无论如何,还是谢谢你的帮助。 - Furqan Hameedi

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