Cross Domain Ajax Request with JSON response for IE,Firefox,Chrome, Safari - jQuery

jquery

We all know why Cross Site Scripting can be dangerous, but there are many reason that you might need to do it anyway. In our case, we are developing a website widget that can be pasted into any person's site with just a small javascript snippet. Once the code is installed (similar to Google Analytics), the necessary support files can be loaded and the data for the widget can be retrieved from our servers. Obviously, the domain names will not be the same and this will cause a Cross Domain Request to occur.

Our widget loads the data asynchronously so that the main page rendering will not be blocked. The widget expects a JSON response from our Windows Communication Foundation (WCF) Service which we have full control over.

It turns out that this is very straight forward for every browser except Internet Explorer (shocker) if you're using jQuery. The basic code for this type of request is the following:

$.ajax({
           type: 'GET',
           url: "someurl",
           processData: true,
           data: {},
           dataType: "json",
           success: function (data) {
               processData(data);
           }
});

function processData(data){
 //Do some stuff with the data
}

The request fires, the response is triggered, and it works across domains. This is an easy and convenient way to process ajax requests. In fact it can be made even more simple using the jQuery wrapper function $.getJSON(); For basic GET requests you can just do the following and get the same result:

$.getJSON("someurl",function(data){
processData(data);});

The $.getJSON() function is shorthand for what we did in the above $.ajax() call.

There is just one major problem, it doesn't work in Internet Explorer. This is extremely frustrating for a couple reasons, foremost for me is that I never use IE and sometimes I forget to verify things work in it until very late in the game. I checked in Firefox, Chrome, Safari, I guess I just assumed a modern browser like IE 7 or IE 8 would work as well, but alas.

So, how do you make it work in IE? It's not terribly difficult but it can be frustrating to figure out. It also requires you to force the response type that you would like in WCF because the IE method does not allow you to set any request header information.

WCF in .NET 4.0 is flexible to the calling client; if you let it know you want XML via the content header Accepts:"text/xml" then it will give you XML back. If you tell it you want Accept:"application/json" then the very same service method will return JSON for you. Pretty cool.

In order to get this to work in IE, you need to use a Microsoft proprietary calling method that does not allow you to alter content headers. This means that you will only get XML back from your service unless you create an additional route for JSON or force a JSON response type for everyone. I'm getting a little side tracked here so I will just note the code required to force a JSON response in the WCF service:

[OperationContract]
[WebGet(UriTemplate = "GetLatest/{id}", ResponseFormat = WebMessageFormat.Json)]
public WidgetData GetLatest(string id)
{
    return WidgetData;
}

Back to making this work in IE. You need to check for the browser type and make a separate ajax call if it is of type IE. jQuery makes checking the browser type easy luckily and the annoyingly proprietary equivellent ajax method for making cross domain requests is:

if ($.browser.msie && window.XDomainRequest) {
    // Use Microsoft XDR
   var xdr = new XDomainRequest();
   xdr.open("get", "someurl");
   xdr.onload = function () {
   //parse response as JSON
   var JSON = $.parseJSON(xdr.responseText);
   if (JSON == null || typeof (JSON) == 'undefined')
   {
        JSON = $.parseJSON(data.firstChild.textContent);
   }
   processData(JSON);
   };
    xdr.send();
}

So the full code for both types of requests ends up being:

if ($.browser.msie && window.XDomainRequest) {
    // Use Microsoft XDR
    var xdr = new XDomainRequest();
    xdr.open("get", "someurl");
    xdr.onload = function () {
    var JSON = $.parseJSON(xdr.responseText);
    if (JSON == null || typeof (JSON) == 'undefined')
    {
        JSON = $.parseJSON(data.firstChild.textContent);
    }
    processData(JSON);
    };
    xdr.send();
} else {
          $.ajax({
          type: 'GET',
          url: "someurl"l,
          processData: true,
          data: {},
          dataType: "json",
          success: function (data) { processData(data); }
          });
}

Update - Allow Origin Headers

You may want to add a response header to the web service response indicating that cross domain requests are OK. The header you want to add to the response is:

Access-Control-Allow-Origin: *

This will allow any website to perform AJAX requests on this service. You can restrict this to specific domains by replacing the * with the URL you want to allow.

In a .NET WCF service, it's easiest to add this to the global.asax of your service like so:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
}

41 Comments

  1. Author's Headshot
    Jan Kacina April 13, 2011
    Reply

    Hi,
    the solution with XDomainRequest works only in IE8 where XDomainRequest has been introduced.

    How do you solve this issue in IE7?

    Thanks in advance,
    Jan

  2. Author's Headshot
    Matt Mombrea April 25, 2011
    Reply

    Jan,

    Hmm, I'm not able to reproduce that issue. Granted I no longer have IE7 installed but when I run IE8 in compatibility mode or IE9 in IE7 mode, it works without issue, probably because the browser includes the XDomainRequest object as you say.

    I've read a few reports saying that prior to IE8, the browser would allow the JQuery $.ajax calls to work properly but I have not tested that out.

  3. Author's Headshot
    Bill Keys June 3, 2011
    Reply

    Thank you for posting your solution. You saved the day :-).

  4. Author's Headshot
    Cross Domain Ajax Request with XML response for IE,Firefox,Chrome, Safari – jQuery | Cypress North Blog July 14, 2011
    Reply

    [...] a previous post I discussed how to accomplish cross domain JSON requests and some caveats to be aware of. That example involved a scenario in which you had control of the [...]

  5. Author's Headshot
    Brett November 15, 2011
    Reply

    I ran into this, was able to fix by using jquery-jsonp plugin:

    http://code.google.com/p/jquery-jsonp/wiki/APIDocumentation

  6. Author's Headshot
    Jangla January 6, 2012
    Reply

    One question: in your 'final code' block you have this line:

    JSON = $.parseJSON(data.firstChild.textContent);

    Where is 'data' coming from?

    • Author's Headshot
      Matt Mombrea January 6, 2012

      Jangla,

      The ajax call (first code block in the post) specifies an on success callback:

      success: function (data) {
      processData(data);
      }

      The data object is returned by the ajax request. Its type and contents depend on what is being returned by your web method.

    • Author's Headshot
      John April 27, 2012

      I could be missing something, but I don't follow. Yes, the $.ajax success callback does have a "data" argument as you point out, but the line in question (that references data.firstChild.textContent) is not in the success callback. Rather, it is outside the $.ajax logic entirely, in the preceeding Microsoft XDR if block. The processData helper also has a "data" argument, but this too is not the context.

    • Author's Headshot
      Matt Mombrea April 27, 2012

      John, in the XDR block the the onload() function (aka success function) first attempts to parse the response into a JSON object in this line:

      var JSON = $.parseJSON(xdr.responseText);

      if that operation fails and the JSON variable is null, it attempts to guess at the response location by using:

      data.firstChild.textContent

      where data is the default variable holding an xdr response.

      In the $.ajax example, the data object is also the default response variable but in that case you can see it's being accepted by the function on this line in context:

      success: function (data) { processData(data); }

  7. Author's Headshot
    Brant February 8, 2012
    Reply

    After poking around and finding all sorts of solutions that didn't seem to work, this one finally did!

    Thanks so much!

  8. Author's Headshot
    semir February 21, 2012
    Reply

    How do you POST data using XDR? You have a get method, can you give an example of a post?

    • Author's Headshot
      Matt Mombrea February 21, 2012

      It would be very similar only you would change the 'get' parameter to 'post' and you would transmit your data as a variable in the send() method. For example:


      if ($.browser.msie && window.XDomainRequest) {
      // Use Microsoft XDR
      var xdr = new XDomainRequest();
      xdr.open("post", "someurl");
      xdr.onload = function () {
      //parse response as JSON
      var JSON = $.parseJSON(xdr.responseText);
      if (JSON == null || typeof (JSON) == 'undefined')
      {
      JSON = $.parseJSON(data.firstChild.textContent);
      }
      processData(JSON);
      };
      xdr.send("my data string to POST");
      }

  9. Author's Headshot
    Bachov Varghese March 22, 2012
    Reply

    Hi;

    I am a php developer.I created a script for access other server(S1) data.Through that script, I like to get data from one server and display that data to the other server(S2).

    this is the script i placed in S2.And this script runs the following script of S1

    $.ajax({
    url:"http://S1/request.php",
    type:'POST',
    crossDomain: true,
    processData: true,
    dataType: 'html',
    data:"request=track&operation=getForm&userId="+user+"&website="+userWebsite,
    success: function(data) {
    alert(data);
    $('.trackForm').html(data);
    }
    });

    When I check the console I didn't get any response...

    But When I Place
    this on S1 i get actual result....

    Is there any mistakes...Plz response

    • Author's Headshot
      Matt Mombrea March 22, 2012

      Bachov, this is likely a cross-origin issue. Take a look at the last section in this article about adding the header Access-Control-Allow-Origin: * to all responses from S1.

      Another way you might be able to work around this is by returning JSON data and using the jQuery method $.getJSON('http://S1/request.php?callback=?', function (data){
      alert(data);
      });

      This method makes a JSONP call which many times will solve the cross origin issue.

  10. Author's Headshot
    mcpDESIGNS June 29, 2012
    Reply

    Hey Matt, great article!! Finally got my GET statement working with Ziptastic API. Doesn't work in IE6 & (i think 7)... Is there something i'm missing to get it working for them, or is it hopeless? Thanks for any help!

  11. Author's Headshot
    priya August 1, 2012
    Reply

    I am not able to access data from other server which is in .net . i m using $.getJSON(‘http://S1/request.php?callback=?’, function (data){
    alert(data);
    });

    • Author's Headshot
      Matthew Mombrea August 2, 2012

      Priya, Are you sure your other server is in .NET? You're making a call to a .php page.

      The issue is likely the cross domain problem. If you have access to the server you're making the call to, you should try and add this header to the response:

      Access-Control-Allow-Origin: *

  12. Author's Headshot
    Daryl Blake August 15, 2012
    Reply

    Thankyou so much for this post Matthew. I got the link to it off Stack Overflow. (FYI) but seriously spent a lot of time on this. And this explains why.

    Once again thanks.
    Daz

  13. Author's Headshot
    scott September 12, 2012
    Reply

    thanks so much. i too was having a heck of a time getting ziptastic to work in ie. thank you!

  14. Author's Headshot
    Transport Error in Google Chrome October 29, 2012
    Reply

    [...] have read other questions here and articles like this: Cross Domain AJAX; but they tend to deal with the problem of IE not working correctly and I have a problem with [...]

  15. Author's Headshot
    sharon December 20, 2012
    Reply

    THANK YOU!!!!

  16. Author's Headshot
    kumar January 18, 2013
    Reply

    This solution is working in ie 8, but how can I get the cookies passed along with the request to the url. Is there any property that we can set to send the cookie along with the request.

  17. Author's Headshot
    Matt Cooper January 30, 2013
    Reply

    Hi
    Many thanks for this, it's amazing with IE reaching V10 that we still need to treat it differently!

    As mentioned in your comments, this doesn't seem to work in IE7 (works in IE8 and 9) though.

  18. Author's Headshot
    Abdul Muthalif June 26, 2013
    Reply

    hi Matt Mombrea...
    I am using REST in Jquery mobile in Phonegap...
    getting error :
    Uncaught ReferenceError: HttpContext is not defined
    Code :

    $(document).ready(function(){

    $("#getContactBtn").click(getContactList);

    });
    function onDeviceReady() {

    console.log("Entering index.html.onDeviceReady");
    getContactList();
    console.log("Exiting index.html.onDeviceReady");
    }
    function getContactList(){

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    console.log("Entering getContactList()");
    var myurl = 'http://localhost:8080/rest/3.2/contactinfo/contactrest';

    $.ajax({

    type: "GET",
    url: myurl + '&callback=?',
    dataType: "xml",
    cache: true,

    error:function (xhr, ajaxOptions, thrownError){
    debugger;
    alert(xhr.statusText);
    alert(thrownError);
    },

    success : function(xml) {
    console.log("Entering getContactList.success()");

    $(xml).find("contactrest").each(function()
    {
    var html = '' + $(this).find("fname").text()
    + ' ' + $(this).find("lname").text() +'';
    $('#emp').append(html);
    });
    console.log("Exiting getContactList.success()");
    }
    });
    console.log("Exiting getContactList()");

    }

  19. Author's Headshot
    aakruti June 28, 2013
    Reply

    Hey Matt, This article is great.
    I am using XDomainRequest to make this work in IE 8&9. Somehow, post call is not working and I get HTTP 400 bad request error.

    Below is my code:

    if ($.browser.msie && window.XDomainRequest) {
    // Use Microsoft XDR
    var xdr = new XDomainRequest();
    var msg = { "numebr": "80000", "psw": "xyz" };
    var data = JSON.stringify(msg);

    xdr.open("post", loanServiceUrl + "ValidateRequest");
    xdr.onload = function () {
    //parse response as JSON
    var JSON = $.parseJSON(xdr.responseText);
    if (JSON == null || typeof (JSON) == 'undefined')
    {
    JSON = $.parseJSON(data.firstChild.textContent);
    }
    processData(JSON);
    };

    xdr.send(data);
    }

  20. Author's Headshot
    aakruti July 1, 2013
    Reply

    my xDomainRequest POST call is working in IE after I made changes suggested in below link.
    http://stackoverflow.com/questions/11105495/how-to-post-a-xdomainrequest-call-to-a-wcf-service-method-with-parameters/11158867#comment25262431_11158867

    Thanks!

  21. Author's Headshot
    Ben July 4, 2013
    Reply

    I tried your first code snippet with cross domain url (ie remote url) but it does not seem to work. Is that supposed to work cross domain or just on local json files?

  22. Author's Headshot
    Internet Explorer Aborting AJAX Requests : FIXED » Cypress North July 26, 2013
    Reply

    [...] written previously on how to handle AJAX requests for Internet Explorer but recently we came across a strange issue where the requests were being aborted by IE before the [...]

  23. Author's Headshot
    Venkat August 14, 2013
    Reply

    Thanks for your post. It helped me to resolve the issue with chrome.

  24. Author's Headshot
    Ranjan Sahoo August 27, 2013
    Reply

    Hello All,

    We are facing an issue on JQuery.

    We have a Web API hosted on a server with Windows Integrated Authentication. The API is giving output in JSON format.
    We want to make a call to this API using JQuery. We are not facing any issue when we are using IE. But we are getting "Unauthorised Access" error (401) when we use Firefox or Chrome browsers.

    It is also observed that it works well with all browsers when we change the authentication type for this API from "Windows Integrated" to "Anonymous"..

    if anyone has faced such issue and can guide us to solve this problem.

    we have set Access-Control-Allow-Origin="*" at web.config of web service.

  25. Author's Headshot
    Egor September 18, 2013
    Reply

    Sir, you've made my day !!! thanx

  26. Author's Headshot
    davidwan December 16, 2013
    Reply

    Access-Control-Allow-Origin: *

    Really helps. I cann't get anything without this statement for firefox, ie, chrome.

  27. Author's Headshot
    vikram January 6, 2014
    Reply

    Hi there,

    I have been facing similar JQuery issue from few months..

    Issue description:

    In master page, i am making a function call which is present in some xyz.js file of same site, as shown below

    populateStockPrice();

    Now in xyz.js file function written as shown below:

    function populateStockPrice() {
    callWebService('http://.asmx/GetQuotes', '{}', function(data) {
    if (data.length == 0)
    $('#stockQuoteError').show();

    for (var i = 0; i 0
    ? 'stockIncrease'
    : 'stockDecrease';

    $('#stockQuotes').append('Action Pfizer');
    $('#stockName').append(': ' + data[i].DisplayPrice + ' ( ');
    $('#stockName').append('' + data[i].DisplayChange +' )');
    }
    }, function(res) {
    $('#stockQuoteError').show();
    });
    }

    // calls an ASP.NET Web Service using jQuery
    function callWebService(url, dataString, callback, errorCallback) {
    if (dataString == null || dataString == '')
    dataString = '{}';

    $.ajax({
    url: url,
    data: dataString,
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    dataFilter: function(data) {
    // This boils the response string down
    // into a proper JavaScript Object().
    var msg = eval('(' + data + ')');

    // If the response has a ".d" top-level property,
    // return what's below that instead.
    if (msg.hasOwnProperty('d'))
    return msg.d;
    else
    return msg;
    },
    success: callback,
    error: errorCallback
    });
    }
    We are displaying the stock values on labels StockQuotes, StockName.

    However, this function is returning values correctly in IE8 (refer to the image shown below) but not working in Google Chrome(refer to the screenshot below)

    Chrome result

    could anyone help me in resolving this issue.

    Thanking you in anticipation

    Vikram 🙂

  28. Author's Headshot
    B Mishra January 6, 2014
    Reply

    Thanks for sharing this! One of the ajax call I had in code was working in all browsers, IE8 too but not IE9, this solved it!

  29. Author's Headshot
    alex May 28, 2014
    Reply

    Is there a reason to use "onload" instead of "onsuccess" for XDomainRequest?

  30. Author's Headshot
    How to: Origin is not allowed by Access-Control-Allow-Origin | SevenNet November 25, 2014
    Reply

    […] I wrote an article on this issue a while back, Cross Domain AJAX. […]

  31. Author's Headshot
    Dimitar Ivanov February 22, 2015
    Reply

    Great article Matthew, thanks. If you need to send cookies alongside the request, you need to set the withCredentials property to true (at the XHR), and the "Access-Control-Allow-Credentials: true" in the response. See more:
    http://zinoui.com/blog/cross-domain-ajax-request

  32. Author's Headshot
    roja March 18, 2015
    Reply

    i trying to get json object format like {"name":"value","name":[{"name1":"A","name":"B"}]} from cross domain data received success but displaying time
    console.log(data); i am getting SyntaxError: missing ; before statement, how to retrieve this type of json data
    is it json or jsonp format(second server os tomcat one is php)

    • Author's Headshot
      Matthew Mombrea March 18, 2015

      It sounds like either your JSON response is missing a semicolon or the calling function is. Probably just a simple syntax error.

  33. Author's Headshot
    JyotiSinghLamba August 30, 2016
    Reply

    Hello,
    I want to create a cross domain widget using .net, WCF service.It will return a HTML output. How can I achieve it using JSONP? Can you help me with this as I don't have much idea.I am .net developer.

Leave a Reply

Your email address will not be published. Required fields are marked *

Meet the Author

mmombrea-headshot
CTO / Partner

Matthew Mombrea

Matt is our Chief Technology Officer and one of the founders of our agency. He started Cypress North in 2010 with Greg Finn, and now leads our Buffalo office. As the head of our development team, Matt oversees all of our technical strategy and software and systems design efforts.

With more than 19 years of software engineering experience, Matt has the knowledge and expertise to help our clients find solutions that will solve their problems and help them reach their goals. He is dedicated to doing things the right way and finding the right custom solution for each client, all while accounting for long-term maintainability and technical debt.

Matt is a Buffalo native and graduated from St. Bonaventure University, where he studied computer science.

When he’s not at work, Matt enjoys spending time with his kids and his dog. He also likes to golf, snowboard, and roast coffee.