Back to Blog

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

March 2, 2011

By Matt Mombrea
41 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","*");
}
Matt Mombrea

Matt Mombrea

Matt is a longtime entrepreneur and software engineer. He also sits on the board of Computer Science at SUNY Fredonia. Born and raised in Buffalo, Matt is passionate about building and maintaining great businesses in Buffalo. Apart from leading Cypress North, Matt architects our company’s datacenter, engineers dozens of custom applications, and directs the rest of the development team.

See Matt's Most Recent Posts

Share this post

41 comments

Jan Kacina April 13, 2011Reply

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 April 25, 2011Reply

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 June 3, 2011Reply

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

Cross Domain Ajax Request with XML response for IE,Firefox,Chrome, Safari – jQuery | Cypress North Blog July 14, 2011Reply

[…] 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 […]

Brett November 15, 2011Reply

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

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

Jangla January 6, 2012Reply

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

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

Where is ‘data’ coming from?

Matt Mombrea January 6, 2012Reply

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 April 27, 2012Reply

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 April 27, 2012Reply

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 February 8, 2012Reply

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

Thanks so much!

Brant February 8, 2012Reply

Oh, also…

If you want to do this by using “feature detection” instead of “browser detection”, you can use this line:

if (‘XDomainRequest’ in window && window.XDomainRequest !== null)

Instead of the line that detects IE.

(I initially found this in my travels here: http://graphicmaniacs.com/note/getting-a-cross-domain-json-with-jquery-in-internet-explorer-8-and-later/ )

semir February 21, 2012Reply

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

Matt Mombrea February 21, 2012Reply

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 March 22, 2012Reply

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 March 22, 2012Reply

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 June 29, 2012Reply

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 August 1, 2012Reply

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 August 2, 2012Reply

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 August 15, 2012Reply

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 September 12, 2012Reply

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

Transport Error in Google Chrome October 29, 2012Reply

[…] 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 […]

sharon December 20, 2012Reply

THANK YOU!!!!

kumar January 18, 2013Reply

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 January 30, 2013Reply

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 June 26, 2013Reply

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 June 28, 2013Reply

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 July 1, 2013Reply

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 July 4, 2013Reply

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?

Internet Explorer Aborting AJAX Requests : FIXED » Cypress North July 26, 2013Reply

[…] 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 […]

Venkat August 14, 2013Reply

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

Ranjan Sahoo August 27, 2013Reply

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 September 18, 2013Reply

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

davidwan December 16, 2013Reply

Access-Control-Allow-Origin: *

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

vikram January 6, 2014Reply

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 January 6, 2014Reply

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!

alex May 28, 2014Reply

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

How to: Origin is not allowed by Access-Control-Allow-Origin | SevenNet November 25, 2014Reply

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

Dimitar Ivanov February 22, 2015Reply

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

roja March 18, 2015Reply

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)

Matthew Mombrea March 18, 2015Reply

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

JyotiSinghLamba August 30, 2016Reply

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

Search our blog

Start A Project

Categories

What's next?

Well...you might like one of these

Article

Is Google Analytics 4 a Tactical Move...

There’s something fishy going on with the way that Google...

Read article

Article

How We Build It: Website Process with...

This month, I sat down with Matt Mombrea, Chief Technical...

Read article

Article

[SOLVED] Using an in-memory repository....

.NET Core Data Protection One of the main benefits of...

Read article