The html times

Elegantly Powered by Google

Cross Domain Restrictions on XMLHttpRequest by Sam Clearman February 9th, 2008 Delicious



No Relevant Downloads

Circumventing Cross Domain Restrictions on XMLHttpRequest: The Easy Way

I had a little problem at work recently where I needed to write a javascript fragment that would, when embedded into an arbitrary website, load an image whose location I could find by running a query with some javascript variables that are set by the containing page.

I couldn't dynamically serve the image based on some url scheme like /images/dynamic/QUERY_STRING.png because they are handled by a content distribution network, so I had to come up with a way of getting the actual image urls into my script.

The obvious choice would be to use XMLHttpRequest to get the information, but unfortunately, the Same Origin Policy prevented me from doing so: you can't load data from domain other than the website's domain using this method.

The solution:

Of course, there's an easy way to load information from an arbitrary domain using javascript: the < script> tag. You could, for example, set up your server to respond to a call to http://mysite.com/scripts/image_url.js?query=QUERY_STRING with the following:

var imageUrl = https://cdn.mysite.com/images/ae0105f04g.png;
			
and voila! You've loaded data from your server into a script originating from any domain that you want.

Now in my case, the query string was being passed to me in the form of a javascript var. This meant that I would have to dynamically create the script tag. I was certain that this wouldn't work: what would be the point of the same origin policy if it was this easy to get around it? To my surprise, I was wrong: the script loaded with no problems:

var scriptElement = document.createElement('script');
scriptElement.src = "http://mysite.com/scripts/image_url.js?query=" + queryString;
document.body.appendChild(scriptElement);
			

Of course, with this method it is difficult to know exactly when your data will be loaded. The following code, for example, will not likely work:

var scriptElement = document.createElement('script');
scriptElement.src = "http://mysite.com/scripts/image_url.js?query=" + queryString;
document.body.appendChild(scriptElement);
document.getElementById("myImage").src = imageURL; // The imageUrl var hasn't been set yet
			
but the solution to this problem is simple: the javascript file you are loading can do more than just set variables, it can also call functions. So, create a callback function and call it with your dynamically generated script:
function setMyImage() {
 document.getElementById("myImage").src = imageURL;
}
var scriptElement = document.createElement('script');
var url = "http://mysite.com/scripts/image_url.js?query=" + queryString + "&callback=setMyImage";
scriptElement.src =  url;
document.body.appendChild(scriptElement);
			

And the response from http://mysite.com/scripts/image_url.js?query=QUERY_STRING&callback=setMyImage:

var imageUrl = https://cdn.mysite.com/images/ae0105f04g.png;
setMyImage();
			

And that's it. If it's that easy to circumvent the same origin policy on XMLHttpRequest, you might ask, why bother to have the policy in the first place? And the answer is... there's absolutely no good reason! Browser makers should simply get rid of the policy, which doesn't do a thing to improve security.

Now when I was writing up this article I discovered that this technique isn't exactly new; people have been using it since at least 2005. So why am I retreading such beaten ground? A couple reasons. One, when I was trying to solve my problem with Google, I didn't find this information. I'm hoping that maybe somebody, somewhere, will find this article and not have to reinvent the wheel yet again. In particular, if you are trying to do something like what I as trying to do, and your Googling has given you results involving iFrame proxies, don't bother with that nonsense; use this method. Two, it gives me an opportunity to talk about one of my pet topics: the march of web application functionality to the (javascript) client layer.

As developers we should thank our lucky stars for this little trick since it enables one of the more exciting things happening on the web: Javascript web service API's. Both Google and Facebook have released Javascript API's for their web services, allowing developers to create client side applications that load data without getting the application's server involved at all. I looked into their code and they both use this same <script> tag hack to load the data.

API’s such as these will enable developers to develop saner applications by moving more code to the client side. In the future, web servers will be data stores with logic that operates on the data to produce more data. All responsibility for presenting the data and providing the use with an interface to generate and manipulate the data, including pulling data from web services such as Google and Facebook, will be the responsibility of the client. I encourage all application developers to help us move in this direction by creating JSON API’s with callbacks in addition to or in lieu of their XML API’s.


Comments

Comments are now closed

Related Articles:

jQuery Chat Client

By Thomas Steinmetz

Thomas Steinmetz gives away his jQuery chat client completer with buddy, session and transcript management. Read more …


Information Wants To Be Free

Elegantly Powered by Google