My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Monday, June 30, 2008

Ajax or JavaScript sub domain request

Some time we could have a situation like this one:

  • a site in a sub domain, called http://a.test.com

  • another site in another sub domain, called http://b.test.com

  • of course, a generic main site, called http://test.com


A common problem between one or more sub domains, is the possibility to use, or call, scripts in the main domain, because of security restrictions.

The simplest solution is to force, in the client side, the document.domain, specifying the common one, i.e.

dcument.domain = "test.com";

In this way you can add, for example, an iframe, and read its content, or use parent window object from the iframe that points, for example, to http://test.com

There are different reasons to do it, and one of them, is the ability to share a global, or common, space, between every sub domain, performing Ajax requests or whatever else we need.

This object, saved in http://test.com, and loaded by every other sub domain, like "a" or "b", could solve in a really simple way this problem.

CrossDomain = function(){
// webreflection.blogspot.com - Mit Style License
var uid = 0, iframe, unset;
return {
get:function(location){
for(var
search = location.search.substring(1).split("&"),
i = 0,
length = search.length,
value;
i < length;
i++
){
value = search[i].split("=");
if(value[0] === "uid"){
search = this[value[1]];
delete this[value[1]];
return search;
}
}
},
unset:function(){
document.domain = unset;
return this;
},
send:function(domain, value){
var id = Math.random() + "." + uid++;
this[id] = value;
if(!iframe){
(document.body || document.documentElement).appendChild(
iframe = document.createElement("iframe")
).style.position = "absolute";
iframe.style.width = iframe.style.height = "1px";
iframe.style.top = iframe.style.left = "-10000px";
};
iframe.src = domain + (~domain.indexOf("?") ? "&" : "?" ) + "uid=" + id;
return this;
},
set:function(){
if(!unset)
unset = document.domain;
document.domain = unset.split(".").slice(1).join(".");
return this;
}
}
}();

Its usage is really simple, and here there is an example from, as example, a.test.com:

// callback to call (if it is the same for other sub domains
// put them in an external file
function showMessage(message){
document.body.appendChild(document.createTextNode(message));
};

// set domain name, i.e. test.com
CrossDomain.set();

// call the page sending some value, every kind of value we need
CrossDomain.send("http://test.com/", ["a", "b", "c"]);


On the other file, the index inside test.com, we could simply use this piece of code:

// set domain name, manually or including CrossDomain
// and using its set method
document.domain = "test.com";

// call, simply, the parent function
// using the get method to avoid conflicts
// with multiple requestes
parent.showMessage(
"You sent me " + parent.CrossDomain.get(location)
); // will alert a,b,c

The good thing of this simple created bridge, is that once you are in test.com, from a.test.com or b.test.com, you can call via Ajax every page inside test.com, sharing a single folder inside the global domain, instead of copy the same stuff everywhere in other domains.

// set domain name
document.domain = "test.com";

// simple Ajax request
var xhr = new XMLHttpRequest;
xhr.open("get", "?demo", true);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4)
parent.showMessage([
"You sent me " + parent.CrossDomain.get(location),
"And AJAX said " + xhr.responseText
].join("\n"));
};
xhr.send(null);


I hope this will be useful :)

5 comments:

vertical-align said...

Very useful, thank you! :)

Unknown said...

Do you have a demo?

Anonymous said...

Absolutely useful, thanks :)

MehtaJee said...

Very much confusing & ambigous.
I would be better if is mentioned clear which code be used on which exact page or domain.

Unknown said...

huh, I don't get what this CrossDomain object is supposed to do, or where you set specifically the domain