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

on March 2, 2011 by Programming with 35 comments

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","*");
}
The following two tabs change content below.

Matthew Mombrea

Matt is a longtime entrepreneur and software engineer. He is a founder of Cypress North, and chief technology officer. Matt also contributes to the community as a columnist on ITworld.com.

35 Comments

  • Jan Kacina
    on 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

  • Matt Mombrea
    on 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.

  • Bill Keys
    on June 3, 2011 Reply

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

  • Brett
    on 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

  • Jangla
    on 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?

    • Matt Mombrea
      on January 6, 2012 Reply

      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.

      • John
        on April 27, 2012 Reply

        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.

        • Matt Mombrea
          on April 27, 2012 Reply

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

  • Brant
    on 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!

  • semir
    on February 21, 2012 Reply

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

    • Matt Mombrea
      on February 21, 2012 Reply

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

  • Bachov Varghese
    on 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

    • Matt Mombrea
      on March 22, 2012 Reply

      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.

  • mcpDESIGNS
    on 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!

  • priya
    on 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);
    });

    • Matthew Mombrea
      on August 2, 2012 Reply

      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: *

  • Daryl Blake
    on 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

  • scott
    on September 12, 2012 Reply

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

  • sharon
    on December 20, 2012 Reply

    THANK YOU!!!!

  • kumar
    on 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.

  • Matt Cooper
    on 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.

  • Abdul Muthalif
    on 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()”);

    }

  • aakruti
    on 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);
    }

  • aakruti
    on 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!

  • Ben
    on 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?

  • Venkat
    on August 14, 2013 Reply

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

  • Ranjan Sahoo
    on 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.

  • Egor
    on September 18, 2013 Reply

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

  • davidwan
    on December 16, 2013 Reply

    Access-Control-Allow-Origin: *

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

  • vikram
    on 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 :)

  • B Mishra
    on 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!

Leave a Reply