IE9 jQuery AJAX with CORS returns "Access is denied"

144,954

Solution 1

This is a known bug with jQuery. The jQuery team has "no plans to support this in core and is better suited as a plugin." (See this comment). IE does not use the XMLHttpRequest, but an alternative object named XDomainRequest.

There is a plugin available to support this in jQuery, which can be found here: https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

EDIT The function $.ajaxTransport registers a transporter factory. A transporter is used internally by $.ajax to perform requests. Therefore, I assume you should be able to call $.ajax as usual. Information on transporters and extending $.ajax can be found here.

Also, a perhaps better version of this plugin can be found here.

Two other notes:

  1. The object XDomainRequest was introduced from IE8 and will not work in versions below.
  2. From IE10 CORS will be supported using a normal XMLHttpRequest.

Edit 2: http to https problem

Requests must be targeted to the same scheme as the hosting page

This restriction means that if your AJAX page is at http://example.com, then your target URL must also begin with HTTP. Similarly, if your AJAX page is at https://example.com, then your target URL must also begin with HTTPS.

Source: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Solution 2

Building off the accepted answer by @dennisg, I accomplished this successfully using jQuery.XDomainRequest.js by MoonScript.

The following code worked correctly in Chrome, Firefox and IE10, but failed in IE9. I simply included the script and it now automagically works in IE9. (And probably 8, but I haven't tested it.)

var displayTweets = function () {
    $.ajax({
        cache: false,
        type: 'GET',
        crossDomain: true,
        url: Site.config().apiRoot + '/Api/GetTwitterFeed',
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (data) {
            for (var tweet in data) {
                displayTweet(data[tweet]);
            }
        }
    });
};

Solution 3

Complete instructions on how to do this using the "jQuery-ajaxTransport-XDomainRequest" plugin can be found here: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest#instructions

This plugin is actively supported, and handles HTML, JSON and XML. The file is also hosted on CDNJS, so you can directly drop the script into your page with no additional setup: http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest.min.js

Solution 4

The problem is that IE9 and below do not support CORS. XDomainRequest do only support GET/POST and the text/plain conten-type as described here: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

So if you want to use all HTTP verbs and/or json etc you have to use another solution. I've written a proxy which will gracefully downgrade to proxying if IE9 or less is used. You do not have to change your code at all if you are using ASP.NET.

The solution is in two parts. The first one is a jquery script which hooks into the jQuery ajax processing. It will automatically call the webserver if an crossDomain request is made and the browser is IE:

$.ajaxPrefilter(function (options, originalOptions, jqXhr) {
    if (!window.CorsProxyUrl) {
        window.CorsProxyUrl = '/corsproxy/';
    }
    // only proxy those requests
    // that are marked as crossDomain requests.
    if (!options.crossDomain) {
        return;
    }

    if (getIeVersion() && getIeVersion() < 10) {
        var url = options.url;
        options.beforeSend = function (request) {
            request.setRequestHeader("X-CorsProxy-Url", url);
        };
        options.url = window.CorsProxyUrl;
        options.crossDomain = false;
    }
});

In your web server you have to receive the request, get the value from the X-CorsProxy-Url http header and do a HTTP request and finally return the result.

My blog post: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/

Solution 5

Building on the solution by MoonScript, you could try this instead:

https://github.com/intuit/xhr-xdr-adapter/blob/master/src/xhr-xdr-adapter.js

The benefit is that since it's a lower level solution, it will enable CORS (to the extent possible) on IE 8/9 with other frameworks, not just with jQuery. I've had success using it with AngularJS, as well as jQuery 1.x and 2.x.

Share:
144,954
Garrett
Author by

Garrett

Updated on April 12, 2020

Comments

  • Garrett
    Garrett about 4 years

    The following works in all browsers except IE (I'm testing in IE 9).

    jQuery.support.cors = true;
    ...
            $.ajax(
                url + "messages/postMessageReadByPersonEmail",
                {
                    crossDomain: true,
                    data: {
                        messageId       : messageId,
                        personEmail     : personEmail
                    },
                    success: function() {
                        alert('marked as read');
                    },
                    error: function(a,b,c) {
                        alert('failed');
                    },
                    type: 'post'
                }
            );
    

    I have another function which uses dataType: 'jsonp', but I don't need any data returned on this AJAX call. My last resort will be to return some jibberish wrapped in JSONP just to make it work.

    Any ideas why IE is screwing up with a CORS request that returns no data?

  • Garrett
    Garrett about 12 years
    Thanks! Any idea how to use that plugin?
  • dennisg
    dennisg about 12 years
    I am not entirely sure, but I've added my assumptions to my answer.
  • Kato
    Kato almost 12 years
    The "better version" of the plugin is innate; I just included it in my page and it automagically fixed my $.ajax calls :) Assuming, of course, that you have all the necessary headers in place.
  • user2918201
    user2918201 over 11 years
    I am missing something: neither of these are working for me. Include the script via a script tag, then just make ajax calls as normal?
  • user2918201
    user2918201 over 11 years
    If I put an alert statement inside the function passed to ajaxTransport, that statement never gets executed. Additionally, the request (which is to 'localhost') doesn't show up in ie9's developer tool's network panel.
  • James Ford
    James Ford over 11 years
    The jQuery.XDomainRequest.js plugin was exactly what I needed! I couldn't get the iexhr.js plugin to work for requests behind HTTP Basic Authentication, but XDomainRequest worked like a charm!
  • Volodymyr Otryshko
    Volodymyr Otryshko over 11 years
    To add to dennisg answer, xdr.js has a bug - ajaxTransport callback will not be called as is. I had to change it in accordance with stackoverflow.com/questions/12481560/… (added "+*" as a first argument of ajaxTransport call).
  • Nicholas Decker
    Nicholas Decker about 11 years
    This worked for me. I didn't need Site.config().apiRoot + (which I'm assuming is for twitter....) But it works great, thanks for doing this.
  • JackMorrissey
    JackMorrissey about 11 years
    @NicholasDecker Site.config().apiRoot was just implementation specific code to get the root URL of the API, nothing universal or fancy. Glad it helped!
  • Jack Marchetti
    Jack Marchetti about 11 years
    I was hoping this would work for me, but I'm trying to POST. wonder if that's the problem for me.
  • Randy L
    Randy L about 11 years
    @VolodymyrOtryshko -- Dude let me buy you a beer! Brilliant comment, fixed all my headaches.
  • mikermcneil
    mikermcneil almost 11 years
    Just a note to anyone with this problem-- in this case, if you have a <= IE7 requirement, and you don't have control over the server (e.g. can't make it support GET + script tags w/ JSONP) your best bet is a lightweight middleware server which translates the JSONP call to a POST and streams the response from the black box server back to the user.
  • Robusto
    Robusto almost 11 years
    The $.ajaxTransport function you linked on github does absolutely nothing for me. And I really wanted it to. Darn.
  • Aaron
    Aaron almost 11 years
    jQuery.XDomainRequest.js makes sure that the current page and remote page are either both http or https. Does this mean that you cannot make a call to an https API from an http page?
  • Kushal Shah
    Kushal Shah almost 11 years
    Note if you're dealing with an HTML response, the improved jQuery.XDomainRequest.js only deals with json and xml. My get now works by adding xdr.js. Wonderful (had done browser sniffing previously and done a XDocumentRequest which works for ie8 and ie10, but inexplicably, no go for ie9).
  • Clintm
    Clintm over 10 years
    It's worth noting that the code that was linked to on moonscripts github repo is an old version that doesn't work. Be sure to get the latest version at: raw.github.com/MoonScript/jQuery-ajaxTransport-XDomainReques‌​t/…
  • Fernando Vezzali
    Fernando Vezzali over 10 years
    Hey @JackMarchetti, for POST requests it doesn't work for me.
  • zanona
    zanona over 10 years
    thanks @SwampDiner, it works fine, it's a shame POST requests are sent as text/plain but it did the trick for me.
  • Hari Honor
    Hari Honor about 10 years
    @Aaron I had problems with IE when I added the bitly API which was using https. Because the page itself was http, IE wouldn't allow it.
  • Cymen
    Cymen about 10 years
    This worked great -- drop in fix. Unbelievable that this issue exists in jQuery but... Thank you!
  • allicarn
    allicarn almost 10 years
    @Aaron, adding on to @HariKaramSingh's comment: changing protocols (http to https), domains (google.com to bing.com), subdomains (mail.google.com to maps.google.com), or protocols (google.com:80 - the default port to google.com:8080) will all trigger a "cross domain" request. Basically everything before the first / in your URL need to be identical.
  • cracker
    cracker almost 10 years
    I am having the same problem and i also refered the above links and put the jquery.xdomainrequest.min.js script in my current page but on post event it goes to jquery.min.js and result to No Access-Control-Allow-Origin header is present on the requested resource. what i need to do in this case?
  • JackMorrissey
    JackMorrissey almost 10 years
    @cracker Are you only having issues with POST? Double check the script is loading after jQuery and your call matches MoonScript's documentation.
  • cracker
    cracker almost 10 years
    it's going into jquery.min.js only but anyways thanks for the reply as i have added the Headers from back end and it's working fine now..
  • Hanna
    Hanna over 9 years
    The extending ajax link is now dead.
  • Joshua Dance
    Joshua Dance over 9 years
    This worked perfect. Dropped the script in, our call pd.$.get(pd.URL, function(data) { //do work with data } works perfectly. Thanks.
  • Frank
    Frank over 9 years
    I've been trying to use this solution, but the cookies setted by the server are never being applied (the ASP.NET_SessionId in particular), so each calls is a new session. I'm on the same protocol, different domain (either different port or domain name), I've tried with jQuery 1.11 or 2.1. Did someone have something similar to this and resolved it, or is there no hope?
  • Frank
    Frank over 9 years
    Actually, it sets the cookies, but each time the server makes a cors request, the server returns a new set of cookies
  • Frank
    Frank over 9 years
    I found my issue and patched the source. There really was something missing. I will fork and make a pull request later today with more details
  • John Washam
    John Washam almost 9 years
    @Frank, at least if you are using XDomainRequest, it does not allow cookies to be sent or received. See this MSDN blog post for more information, specifically the section titled "No authentication or cookies will be sent with the request."
  • Stefan
    Stefan over 8 years
    If I had read the coments, I would have saved myself a lot of time, but I wasted several hours trying to make ajax calls to an https service from an http site. I added it to the answer to avoid other people runnng into the sampe problem.
  • Stanislav
    Stanislav over 8 years
    I had a problem with applying this solution because in my ajax call contained an option 'async: false', while in xdr.js there is an if condition that applies the fix only if async us true.