While JavaScript's XmlHttpRequest
object does not allow you to
load data from outside of the page's current domain because of the
same origin policy, it turns out that SCRIPT
tags are not subject to the "same
origin" policy. Consequently, an informal standard known as JSONP has
been developed that allows data to be cross-domain loaded. As you
might imagine, it is this very capability that empowers web
applications[13] to mash up data from multiple
sources and present it in a single coherent application.
Like anything else, JSONP sounds a bit mysterious at first,
but it is pretty simple once you understand it. To introduce the
concept, imagine that a SCRIPT
tag is dynamically created and appended to the HEAD
of a page that was originally loaded
from http://oreilly.com. The interesting twist
comes in with the source of the tag: instead of loading from the
oreilly.com domain, it's
perfectly free to load from any domain, say http://example.com?id=23. Using JavaScript, the
operation so far is simple:
e = document.createElement("SCRIPT"); e.src="http://example.com?id=23"; e.type="text/javascript"; document.getElementsByTagName("HEAD")[0].appendChild(e);
Although the SCRIPT
tag
normally implies that you are loading an actual script, you can
actually return any kind of content you'd like, including JSON
objects. There's just one problem with thatâthe objects would just
get appended to the HEAD
of the
page and nothing interesting would happen (except that you might
wreck the way your page looks).
For example, you might end up with something like the
following blurb, where the emphasized text is the result of the
previous JavaScript snippet that dynamically added the SCRIPT
tag to the HEAD
of the page:
<html> <head> <title>My Page</title> <script type="text/javascript" > {foo : "bar"} </script> </head> <body> Some page content. </body> </html>
While shoving a JavaScript object literal into the HEAD
is of little use, imagine what would
happen if you could somehow receive back JSON data that was wrapped
in a function callâto be more precise, a function call that is
already defined somewhere on your page. In effect, you'd be
achieving a truly marvelous thing because you could now
asynchronously request external data whenever you want it and
immediately pass it into a function for processing. To accomplish
this feat, all that it takes is having the result of inserting the
SCRIPT
tag return the JSON data
padded with an extra function call such as
myCallback({foo : "bar"})
instead
of just {foo : "bar"}
. Assuming
that myCallback
is already
defined when the SCRIPT
tag
finishes loading, you're all set because the function will execute,
pass in the data as a parameter, and effectively provide you with a
callback function. (It's worth taking a moment to let this process
sink in if it hasn't quite clicked yet.)
But there's still a small problem: how do you get the JSON
object to come wrapped with that extra padding that triggers a
callback? Easyâall the kind folks at example.com have to do is provide
you with an additional query string parameter that allows you to
define the name of the function that the result should be wrapped
in. Assuming that they've determined that you should pass in your
function via the c
parameter (a
new request that provides c
as a
query string parameter for you to use), calling http://example.com?id=23&c=myCallback would
return myCallback({foo : "bar"})
.
And that's all there is to it.
[13] Without loading any external plugins, JSONP is your only means of loading cross-domain data. Plug-ins such as Flash and ActiveX, however, have other ways of working around the "same origin" limitation that is placed on the browser itself.
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.