[jquery] Jquery $.ajax fails in IE on cross domain calls

I am doing a cross domain request using $.ajax. It works on Firefox and Chrome, but does not issue a call on IE 7 or 8. Can anyone tell me what's wrong with the following?

  1. I have used JSON and JSONP (which I stopped using, due to some custom restrictions).
  2. I am already using Allow-access-control-origin header on my site. (Without those, Chrome and Firefox were not making successful requests.)
  3. I have already tried https://developer.mozilla.org/en/http_access_control

Code:

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

I have tried various tips present on multiple sites, but no luck yet.

This question is related to jquery cross-domain

The answer is


Jquery does this for you, only thing is to set $.support.cors = true; Then cross domain request works fine in all browsers for jquery users.


@Furqan Could you please let me know whether you tested this with HTTP POST method,

Since I am also working on the same kind of situation, but I am not able to POST the data to different domain.

But after reading this it was quite simple...only thing is you have to forget about OLD browsers. I am giving code to send with POST method from same above URL for quick reference

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

Microsoft always ploughs a self-defeating (at least in IE) furrow:

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

CORS works with XDomainRequest in IE8. But IE 8 does not support Preflighted or Credentialed Requests while Firefox 3.5+, Safari 4+, and Chrome all support such requests.


For IE8 & IE9 you need to use XDomainRequest (XDR). If you look below you'll see it's in a sort of similar formatting as $.ajax. As far as my research has got me I can't get this cross-domain working in IE6 & 7 (still looking for a work-around for this). XDR first came out in IE8 (it's in IE9 also). So basically first, I test for 6/7 and do no AJAX.

IE10+ is able to do cross-domain normally like all the other browsers (congrats Microsoft... sigh)

After that the else if tests for 'XDomainRequest in window (apparently better than browser sniffing) and does the JSON AJAX request that way, other wise the ELSE does it normally with $.ajax.

Hope this helps!! Took me forever to get this all figured out originally

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

For anyone whom might still have this problem using jQuery 2.0 (I know I do), Jay Dave wrote the best jQuery workaround but I still have a few things to add to his code namely:

  • make sure you are using the same protocol for requests (HTTP -> HTTP or HTTPS -> HTTPS), Ayush Gupta gave a link to knows issues
  • handle the "onprogress" events with a no-op function (this will prevent IE from abording the requests after it receives the first bits from the server.

The complete code is below:

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

It's hard to tell due to the lack of formatting in the question, but I think I see two issues with the ajax call.

1) the application/x-www-form-urlencoded for contentType should be in quotes

2) There should be a comma separating the contentType and async parameters.


Others coming around here might do well to read http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx which talks about limitations of XDomainRequest


Simply install this jQuery Plugin: jQuery Cross-Domain AJAX for IE8

This 1.4kb plugin works right away in Internet Explorer 8 and 9.

Include the plugin after jQuery, and call your ajax request as normal. Nothing else required.


Add extra transport to jquery for IE. ( Just add this code in your script at the end )

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

This solved my problem with Jquery $.ajax failing for Cross Domain AJAX request.

Cheers.


I have the same problem in IE, I solved it by replacing:

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

To

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

So basically upgrade your jquery version.


Simply add "?callback=?" (or "&callback=?") to your url:

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

When doing the calls (with everything else set properly for cross-domain, as above) this will trigger the proper JSONP formatting.

More in-depth explanation can be found in the answer here.


Note, adding

$.support.cors = true;

was sufficient to force $.ajax calls to work on IE8


I had a similar problem in IE9 where some CORS calls were aborting, while others weren't. My app is also dependent on a promise interface, so the XDomainRequest suggestions above weren't EXACTLY what I needed, so I added a deferred into my service.get workaround for IE9. Hopefully it can be useful to someone else running across this problem. :

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