JSONP: How Does it Work?

Interestingly enough, I’ve seen a few candidates in interviews the last few months flail a bit when asked about getting around the same origin policy using JavaScript in a browser. Most know enough to toss out the term “JSONP” and perhaps another solution (e.g. proxy or CORS) but can’t really explain why one might prefer a certain solution over another. In fact, few could even describe how JSONP works aside from some JQuery library they always “just include”.

What is JSONP?

If you spend some time thinking about how JavaScript operates in a browser, you will probably arrive at the realization that the policy does not seem to effect script tags. Specifically, how many of us get JQuery from the Google CDN or some other source that is not the same origin as our current page? (I hope that answer is “most”, by the way.)

That same logic, combined with some DOM knowledge, would probably lead you to experiment with loading other types of JavaScript, aside from a library, using script tags. Since JavaScript has a global scope, if you were to reference a function that could handle that data you could then link it with your application and do something interesting with it.

JSONP is born.

The idea of JSONP is actually pretty simple: toss a script tag into the DOM with a reference to a resource that returns JSON data. Have the server return said JSON with “padding” (the “P” part of JSONP) that executes a function wrapping the incoming data. In order for this to work properly, the server API must also support JSONP. Typically, the function name is named as the callback parameter. For example, let’s pretend you are accessing a service that returns JSON weather information that looks like:

http://www.weather.com/90210

Which returns JSON like:

{"zipCode": "90210","location": "Beverly Hills","high": "85 degrees","low": "55 degrees"}

Adding JSONP support would result in a URL that looks like:

http://www.weather.com/90210?callback=MyCallback

And returns:

MyCallback({"zipCode": "90210","location": "Beverly Hills","high": "85 degrees","low": "55 degrees"});

This data is now exposed to the rest of the application as long as MyCallback is a valid function name in the global scope.

Most JSONP implementations in libraries like JQuery will automatically generate callback functions as well as cleaning up inserted script tags when the callback executes, but the basic idea is actually pretty simple.

Why To Use JSONP?

JSONP is universally supported on just about every browser and a lot of useful APIs have support for it already in place (Yahoo, Twitter, Google, etc.) Aside from the regular XMLHttpRequest and DOM differences, nothing really special needs to be done to make it work across different browsers. Finally, since it has been around for a bit, there are pretty mature JSONP plugins for just about every major library and framework around (JQuery, YUI, Prototype, etc.)

Why NOT To Use JSONP?

Deciding against using JSONP is directly related to how it works. First of all, the only HTTP method you can use is GET since that is the only method script tags support. This immediately eliminates the use of JSONP as an option to interact with nice RESTful APIs that use other HTTP verbs to do fun stuff like CRUD. And while we’re on the subject of GET, note that using anything other than URL parameters to communicate with the server API (e.g. sending some JSON over) is also not possible. (You could encode JSON as a URL parameter, but shame on you for even thinking that.)

Secondly, since you are relying on a script tag, there is no uniform way to catch errors. Some browsers will allow attaching a callback to the script tag (e.g. onError() {}), but it is not universally supported (any guesses on which browsers don’t support it?) and therefore can’t be relied upon without some unfortunate hacks. If the called API is doing syntactically correct things like returning an HTTP 404 response code when a resource cannot be found, there is no way to easily catch that error condition or parse the response body for further information. Instead, what typically takes place are APIs that return HTTP 200 status codes but contain JSON describing an error condition. There are worse things in the world, but I cringe at that approach these days.

Finally, keep in mind that JSONP is really a security vulnerability. It happens to be an extremely useful one, but the same origin policy does provide value in protecting the application and using JSONP is willfully opening up a hole that could potentially become an attack vector.

What Are Some Alternatives?

The easiest alternative is setting up a proxy to an external API through the same origin as the web application. This can be done pretty easily using tooling built into web servers like Apache and Nginx.

If you are able to remove support for IE7 and don’t care much about Opera, the end game is Cross-Origin Resource Sharing (CORS). This solution allows the full array of HTTP verbs and errors (including POSTing JSON) and has a greater level of security than JSONP. It has decent support on IE8+ (with some provisos) and is relatively easy to implement on the server. The downside is that many popular public JSON APIs today don’t yet support it.

Conclusion

CORS >= Proxy > JSONP (most of the time).

About these ads

About johnnywey

Welcome to A Regular Expression. This blog is designed to reflect my thoughts on life, music, software design, Apple, faith, philosophy, and whatever else I can think of.

Posted on May 20, 2012, in AJAX, JavaScript, Programming. Bookmark the permalink. 5 Comments.

  1. I desired to discuss this specific posting, “JSONP: How Does
    it Work? « a regular expression” along with my own friends on facebook itself.
    I reallybasically wanted to spread your remarkable writing!
    Thx, Antoine

  2. Good article. But its a bit unclear how Javascript internally is doing the request. I know its not using the build-in

    browser XMLHttpRequest, but how does it do it? Read an article on stackoverflow where they simply create a Javascript

    object and set the
    var obj = document.createElement(‘script’);
    obj.src = “http://somedomain.com?blabla=yes”

    http://stackoverflow.com/questions/4490143/using-javascript-to-perform-a-get-request-without-ajax

    Here from jQuery:
    $.ajax({
    type: ‘GET’,
    url: url,
    async: false,
    jsonpCallback: ‘jsonCallback’,
    contentType: “application/json”,
    dataType: ‘jsonp’,
    success: function(json) {
    console.log(“console. hurra”);
    },
    error: function(e) {
    console.log(e.message);
    }
    });

    Do you know how does jQuery internally build up the request in Javascript and submit it?

    I tried this locally and it worked like charm in the sense that the the script was inserted correctly in my page.
    var CampaignNs = {

    GET: function(url) {
    var head = document.getElementsByTagName(‘head’)[0];
    var n = document.createElement(‘script’);
    n.src = url;
    n.type = ‘text/javascript';
    n.onload = function() { // this is not really mandatory, but removes the tag when finished.
    head.removeChild(n);
    };
    head.appendChild(n);
    }
    }

    I advance thanks

  3. Good … hope my article helped a little!

  4. erythromycin medication drug cafdkecbgcge

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: