javascript - What is JSONP, and why was it created?

ID : 334

viewed : 137

Tags : javascriptjsonjsonpterminologyjavascript





Top 5 Answer for javascript - What is JSONP, and why was it created?

vote vote

94

It's actually not too complicated...

Say you're on domain example.com, and you want to make a request to domain example.net. To do so, you need to cross domain boundaries, a no-no in most of browserland.

The one item that bypasses this limitation is <script> tags. When you use a script tag, the domain limitation is ignored, but under normal circumstances, you can't really do anything with the results, the script just gets evaluated.

Enter JSONP. When you make your request to a server that is JSONP enabled, you pass a special parameter that tells the server a little bit about your page. That way, the server is able to nicely wrap up its response in a way that your page can handle.

For example, say the server expects a parameter called callback to enable its JSONP capabilities. Then your request would look like:

http://www.example.net/sample.aspx?callback=mycallback 

Without JSONP, this might return some basic JavaScript object, like so:

{ foo: 'bar' } 

However, with JSONP, when the server receives the "callback" parameter, it wraps up the result a little differently, returning something like this:

mycallback({ foo: 'bar' }); 

As you can see, it will now invoke the method you specified. So, in your page, you define the callback function:

mycallback = function(data){   alert(data.foo); }; 

And now, when the script is loaded, it'll be evaluated, and your function will be executed. Voila, cross-domain requests!

It's also worth noting the one major issue with JSONP: you lose a lot of control of the request. For example, there is no "nice" way to get proper failure codes back. As a result, you end up using timers to monitor the request, etc, which is always a bit suspect. The proposition for JSONRequest is a great solution to allowing cross domain scripting, maintaining security, and allowing proper control of the request.

These days (2015), CORS is the recommended approach vs. JSONRequest. JSONP is still useful for older browser support, but given the security implications, unless you have no choice CORS is the better choice.

vote vote

87

JSONP is really a simple trick to overcome the XMLHttpRequest same domain policy. (As you know one cannot send AJAX (XMLHttpRequest) request to a different domain.)

So - instead of using XMLHttpRequest we have to use script HTML tags, the ones you usually use to load js files, in order for js to get data from another domain. Sounds weird?

Thing is - turns out script tags can be used in a fashion similar to XMLHttpRequest! Check this out:

script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.someWebApiServer.com/some-data'; 

You will end up with a script segment that looks like this after it loads the data:

<script> {['some string 1', 'some data', 'whatever data']} </script> 

However this is a bit inconvenient, because we have to fetch this array from script tag. So JSONP creators decided that this will work better(and it is):

script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback'; 

Notice the my_callback function over there? So - when JSONP server receives your request and finds callback parameter - instead of returning plain js array it'll return this:

my_callback({['some string 1', 'some data', 'whatever data']}); 

See where the profit is: now we get automatic callback (my_callback) that'll be triggered once we get the data.
That's all there is to know about JSONP: it's a callback and script tags.

NOTE: these are simple examples of JSONP usage, these are not production ready scripts.

Basic JavaScript example (simple Twitter feed using JSONP)

<html>     <head>     </head>     <body>         <div id = 'twitterFeed'></div>         <script>         function myCallback(dataWeGotViaJsonp){             var text = '';             var len = dataWeGotViaJsonp.length;             for(var i=0;i<len;i++){                 twitterEntry = dataWeGotViaJsonp[i];                 text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'             }             document.getElementById('twitterFeed').innerHTML = text;         }         </script>         <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>     </body> </html> 

Basic jQuery example (simple Twitter feed using JSONP)

<html>     <head>         <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>         <script>             $(document).ready(function(){                 $.ajax({                     url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',                     dataType: 'jsonp',                     success: function(dataWeGotViaJsonp){                         var text = '';                         var len = dataWeGotViaJsonp.length;                         for(var i=0;i<len;i++){                             twitterEntry = dataWeGotViaJsonp[i];                             text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'                         }                         $('#twitterFeed').html(text);                     }                 });             })         </script>     </head>     <body>         <div id = 'twitterFeed'></div>     </body> </html> 


JSONP stands for JSON with Padding. (very poorly named technique as it really has nothing to do with what most people would think of as “padding”.)

vote vote

71

JSONP works by constructing a “script” element (either in HTML markup or inserted into the DOM via JavaScript), which requests to a remote data service location. The response is a javascript loaded on to your browser with name of the pre-defined function along with parameter being passed that is tht JSON data being requested. When the script executes, the function is called along with JSON data, allowing the requesting page to receive and process the data.

For Further Reading Visit: https://blogs.sap.com/2013/07/15/secret-behind-jsonp/

client side snippet of code

    <!DOCTYPE html>     <html lang="en">     <head>      <title>AvLabz - CORS : The Secrets Behind JSONP </title>      <meta charset="UTF-8" />     </head>     <body>       <input type="text" id="username" placeholder="Enter Your Name"/>       <button type="submit" onclick="sendRequest()"> Send Request to Server </button>     <script>     "use strict";     //Construct the script tag at Runtime     function requestServerCall(url) {       var head = document.head;       var script = document.createElement("script");        script.setAttribute("src", url);       head.appendChild(script);       head.removeChild(script);     }      //Predefined callback function         function jsonpCallback(data) {       alert(data.message); // Response data from the server     }      //Reference to the input field     var username = document.getElementById("username");      //Send Request to Server     function sendRequest() {       // Edit with your Web Service URL       requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");     }        </script>    </body>    </html> 

Server side piece of PHP code

<?php     header("Content-Type: application/javascript");     $callback = $_GET["callback"];     $message = $_GET["message"]." you got a response from server yipeee!!!";     $jsonResponse = "{\"message\":\"" . $message . "\"}";     echo $callback . "(" . $jsonResponse . ")"; ?> 
vote vote

69

Because you can ask the server to prepend a prefix to the returned JSON object. E.g

function_prefix(json_object);

in order for the browser to eval "inline" the JSON string as an expression. This trick makes it possible for the server to "inject" javascript code directly in the Client browser and this with bypassing the "same origin" restrictions.

In other words, you can achieve cross-domain data exchange.


Normally, XMLHttpRequest doesn't permit cross-domain data-exchange directly (one needs to go through a server in the same domain) whereas:

<script src="some_other_domain/some_data.js&prefix=function_prefix>` one can access data from a domain different than from the origin.


Also worth noting: even though the server should be considered as "trusted" before attempting that sort of "trick", the side-effects of possible change in object format etc. can be contained. If a function_prefix (i.e. a proper js function) is used to receive the JSON object, the said function can perform checks before accepting/further processing the returned data.

vote vote

59

TL;DR

JSONP is an old trick invented to bypass the security restriction that forbids us to get JSON data that is in a different website (a different origin1) than the one we are currently browsing.

The trick works by using a <script> tag that asks for the JSON from that place, e.g.: { "user":"Smith" }, but wrapped in a function, the actual JSONP ("JSON with Padding"):

peopleDataJSONP({"user":"Smith"}) 

Receiving it in this form enables us to use the data within our peopleDataJSONP function. JSONP is a bad practice and not needed anymore, don't use it (read below).


The problem

Say we want to use on ourweb.com some JSON data (or any raw data really) hosted at anotherweb.com. If we were to use GET request (think XMLHttpRequest, or fetch call, $.ajax, etc.), our browser would tell us it's not allowed with this ugly error:

Chrome CORS console error

How to get the data we want? Well, <script> tags are not subjected to this whole server (origin1) restriction! That's why we can load a library like jQuery or Google Maps from any server, such as a CDN, without any errors.

Here's the important point: if you think about it, those libraries are actual, runnable JS code (usually a massive function with all the logic inside). But raw data? JSON data is not code. There's nothing to run; it's just plain text.

Therefore, there's no way to handle or manipulate our precious data. The browser will download the data pointed at by our <script> tag and when processing it'll rightfully complain:

wtf is this {"user":"Smith"} crap we loaded? It's not code. I can't compute, syntax error!


The JSONP hack

The old/hacky way to utilize that data? If we could make plain text somehow runnable, we could grab it on runtime. So we need anotherweb.com to send it with some logic, so when it's loaded, your code in the browser will be able to use said data. We need two things: 1) to get the data in a way that it can be run, and 2) write some code in the client so that when the data runs, this code is called and we get to use the data.

For 1) we ask the foreign server to send us the JSON data inside a JS function. The data itself is set up as that function's input. It looks like this:

peopleDataJSONP({"user":"Smith"}) 

which makes it JS code our browser will parse and run without complaining! Exactly like it does with the jQuery library. To receive the data like that, the client "asks" the JSONP-friendly server for it, usually done like this:

<script src="https://anotherweb.com/api/data-from-people.json?myCallback=peopleDataJSONP"></script> 

As per 2), since our browser will receive the JSONP with that function name, we need a function with the same name in our code, like this:

function peopleDataJSONP(data){   alert(data.user); // "Smith" } 

The browser will download the JSONP and run it, which calls our function, where the argument data will be the JSON data from anotherweb.com. We can now do with our data whatever we want to.


Don't use JSONP, use CORS

JSONP is a cross-site hack with a few downsides:

  • We can only perform GET requests
  • Since it's a GET request triggered by a simple script tag, we don't get helpful errors or progress info
  • There are also some security concerns, like running in your client JS code that could be changed to a malicious payload
  • It only solves the problem with JSON data, but Same-Origin security policy applies to other data (WebFonts, images/video drawn with drawImage()...)
  • It's not very elegant nor readable.

The takeaway is that there's no need to use it nowadays.

You should read about CORS here, but the gist of it is:

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own.



  1. origin is defined by 3 things: protocol, port, and host. So, for example, https://web.com is a different origin than http://web.com (different protocol) and https://web.com:8081 (different port) and obviously https://thatotherweb.net (different host)

Top 3 video Explaining javascript - What is JSONP, and why was it created?







Related QUESTION?