Cross-Domain Scripting: how it's done in jQuery

Web services outputting JSON has become quite common these days; however, consuming such delicious data was not possible purely in JavaScipt because of the same origin/domain policy. Not anymore. As of jQuery 1.2, loading JSON from a different domain is possible.

Historically, it was normal to retrieve the data (which typically was in XML) from a web service using PHP (or other languages) and cache it locally, then format the stored data for display all on the server-side.

JSON came in as sites became more JavaScript heavy and the data that are being passed to scripts became more complex. In addition, JSON has less over head than XML in terms of size and processing for decoding/encoding, which made it a good option for outputting web service responses.

Then JSONP emerged, which is basically JSON 'padded' in a function call:

someFuncName(jsonString);

Where someFuncName is function that you implement on your site to process the jsonString from an external service.

The JavaScript library, jQuery, provides the function, getJSON, to allow your site to retrieve a JSONP (JSON with Padding) data and do some stuff with it right on the browser (client-side). Here is an example using Flickr's API:

<script type="text/javascript">
$(document).ready(function () {
	$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=ofna&tagmode=any&format=json&jsoncallback=?", function (data) {
		$.each(data.items, function(i,item){
			$("#jsonsample1").append("<img src='"+item.media.m+"' />");
			if ( i == 3 ) return false;
		})
	});
});
</script>

In the above example, the JSON source is coming from http://api.flickr.com/services/feeds/photos_public.gne?tags= ofna&tagmode=any&format=json&jsoncallback=?, and the output is processed in the anonymous function.

Looking at the query string, it is fairly obvious that we are asking for data formatted in JSON by specifying format=json, and that it is wrapped in a function call specified with the jsoncallback=? parameter.

However, the parameter jsoncallback is set to ?, which is confusing. Firstly, ? is not a valid function name. Secondly, how is the anonymous function being executed at all?

What really happening is that, jQuery is changing the ? to some string, e.g. jsonp1252650268433, and the anonymous function is given a name with the same value resulting in jQuery sending the request, http://api.flickr.com/services/feeds/photos_public.gne?tags= ofna&tagmode=any&format=json&jsoncallback=jsonp1252650268433

Upon request, Flickr then outputs the following JSONP:

jsonp1252650268433(jsonString);

Our not-so anonymous function with the jQuery supplied name of jsonp1252650268433 is then called to create images from the JSON data ('jsonString' above). And there you have it, folks: cross-browser scripting.

As for the developers out there who are writing web services, if you want others to easily consume your API using JavaScript, you must do two important things:

  1. provide JSON formatting as an option
  2. accept a parameter like Flickr's 'jsoncallback' for padding the JSON output

And then there's more:

Using getJSON is not the only way to do this. See the example below:

<script type="text/javascript">
function processJson(data){
	$.each(data.items, function(i,item){
		$("#jsonsample2").append("<img src='"+item.media.m+"' />");
		if ( i == 3 ) return false;
	});
}
</script>
<script type="text/javascript" src="http://api.flickr.com/services/feeds/photos_public.gne?tags=traxxas&tagmode=any&format=json&jsoncallback=processJson"></script>

With the above example, we have implemented the processJson function, which gets called after the 'script', http://api.flickr.com/services/feeds/photos_public.gne?tags=traxxas&tagmode=any&format=json&jsoncallback=processJson, is loaded.

Loading the same URL as an ordinary JavaScript file achieves roughly the same thing. One difference is when using getJSON, you may bypass one or two levels of caching as the actual generated request is dynamic, i.e. the value of the jsoncallback parameter in the query string changes on each request. Another option without using getJSON is getScript. As of jQuery 1.2, getScript can load a script from another domain.

There is one big caveat to all of this though: you are running a JavaScript on your site from another site, and you don't have control over it. The JSONP structure may change breaking your scripts that are dependent on it, or it may became totally different and maliciously modify your site's HTML to be something totally different.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
Prove you're not a bad bot.

Tag Cloud

Syndicate content

Powered by Pressflow, an open source content management system