UPDATE 01/23/2015
I’ve realized that CORS can at times be blocked by firewalls and thus have adopted a new personal best practice for performing CORS requests using a server side proxy setup – which is browser agnostic and thus conditional code is not needed on a per-browser basis. I suggest you read Successful Cross Site Scripting (CORS) Using A Server Proxy for how to best implement a server side proxy CORS request.
I ran into an annoying problem today… We were getting complaints that our application wasn’t working (of course the customers never tell you what browser, what they are doing, etc.). But I knew it was breaking where I to an AJAX call to my NodeJS server, which I’m calling to via IP address due to our multi-server setup. This technically creates a cross site scripting issue.
I’m using jQuery to do this AJAX call, and I know I have the jQuery settings for cross-site scripting enabled.
1 | jQuery.support.cors = true; /* Allow cross domain scripting */ |
So what gives?
Bottom line – our good ‘ole evil friend, Internet Explorer, has a situation where cross site scripting is not supported by our not-so-evil friend jQuery. Now to be fair to IE, this only affects users who have their security settings to block cross site scripting. Which I believe is the default setting… So we could add a message to the site for them to change their settings. It’s simple really:
- Click on the little gear thingy if in IE9. If your in IE8 use the settings menu.
- Choose Internet Options
- Select the Security tab
- Click the Custom Level… button (why did they add the ellipses there???)
- Scroll about 2/3rds the way down the long list to the Miscellaneous section
- For the option Access data sources across domains, choose Enable (or Prompt if you want the annoying alert box everytime you come across this)
- Click OK
- Click OK
- Reload your page and try again.
Easy peasy, right?
I guess the other option is to use Javascript / jQuery to sniff for only our unfortunate IE friends and do a custom function for just them. Now I should say, IE10 and greater is safe from this, so we don’t need to treat them special. Oh, and for IE7 and lower this fix does not work – they are essentially a lost cause in many regards. But IE 8 & IE 9 are fixed with this solution.
The Solution
I’m not going to take credit for the solution – rather am going to do my best to pass along those with higher knowledge than me. Thank you so much to Tom Elliott at Web Dev Door for clearly documenting the solution I used for this. So the solution is this article:
http://www.webdevdoor.com/jquery/cross-domain-browser-json-ajax/
I didn’t personally need to do anything with the Step 1 portion of his article, but that’s not to say that your case won’t require it. This is of course dependent on your server and code setup.
But the Step 2 portion of his article is a brilliant little script that simply detects if you are a IE8 or IE9 visitor. If so, the AJAX request is sent via xdr – the Microsoft protocol for cross-domain Asynchronous JavaScript and XML requests. If you are NOT on one of those two browsers, the AJAX request is handled via jQuery (or if you have some other means by all means go ahead.
I did do one addition to Tom’s code. For the IE visitors using xdr, I added an onerror event in the case that something does go wrong. This is something I was doing in my jQuery AJAX call already, so needed to add it here as well.
1 2 3 | xdr.onerror = function() { processFinalImageOutputError(xdr.responseText); }; |
I created two functions – one for AJAX success and one for AJAX error and both the xdr and jQuery functions can call those functions in their appropriate instance.
So my final output looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | var url = 'http://cross-domain-url.com/script?param1=something¶m2=somethingElse'; var browser = navigator.userAgent; var IEversion = 99; //Give a default value for non-IE browsers if (browser.indexOf("MSIE") > 1) { //Detects if IE IEversion = parseInt(browser.substr(browser.indexOf("MSIE")+5, 5)); } if (IEversion < 10) { /* For older IE, sending AJAX request using xdr */ xdr = new XDomainRequest(); // Creates a new XDR object. xdr.timeout = 3000;//Set the timeout time to 3 second. xdr.onload = function () { successFunction(xdr.responseText); }; xdr.onerror = function () { errorFunction(xdr.responseText); }; xdr.ontimeout = function () { alert("Error"); }; // this also needs to be set xdr.onprogress = function() { window.console.log('progress'); }; xdr.open("GET", url); // Creates a cross-domain connection with our target server using GET method. xdr.send(); //Send string data to server } else { /* For modern browsers, send AJAX request using jQuery */ jQuery.ajax({ url: url, dataType: 'json', crossDomain: true, success: function( data ) { successFunction(data); }, error: function(xhr, status, errorThrown) { errorFunction(xhr, status, errorThrown); } }); } function successFunction(data) { console.log("AJAX Request Success"); } function errorFunction(xhr, status, errorThrown) { console.log("AJAX Request ERROR"); console.log(xhr); console.log(status); console.log(errorThrown); } |
UPDATED 07/11/2014
Modified the XDR functions a bit – according to Rich Apodaca on this post, I was missing a few of the required functions.