Related
I understand JSON, but not JSONP. Wikipedia's document on JSON is (was) the top search result for JSONP. It says this:
JSONP or "JSON with padding" is a JSON extension wherein a prefix is specified as an input argument of the call itself.
Huh? What call? That doesn't make any sense to me. JSON is a data format. There's no call.
The 2nd search result is from some guy named Remy, who writes this about JSONP:
JSONP is script tag injection, passing the response from the server in to a user specified function.
I can sort of understand that, but it's still not making any sense.
So what is JSONP? Why was it created (what problem does it solve)? And why would I use it?
Addendum: I've just created a new page for JSONP on Wikipedia; it now has a clear and thorough description of JSONP, based on jvenema's answer.
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.
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”.)
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 . ")";
?>
This is my ELI5 (explain me like I'm 5) attempt for those that need it.
TL;DR
JSONP is an old trick invented to bypass the security restriction in web browsers that forbids us to get data that is in a different website/server (called different origin1) than our own.
The trick works by using a <script> tag to load a JSON (e.g.: { "city":"Barcelona" }) from somewhere else, that will send us the data wrapped in a function, the actual JSONP ("JSON with Padding"):
tourismJSONP({"city":"Barcelona"})
Receiving it in this way enables us to use the data within our tourismJSONP function. JSONP is a bad practice and not needed anymore, don't use it (read at the end).
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:
This is a Content Security Policy restriction error, it's designed to protect users from certain attacks. You should just configure it properly (see at the end).
How would the JSONP trick help us here? 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.
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 is not code. There's nothing to run; it's just plain text.
Hence, the browser will download the data pointed at by our <script> tag and when processing it'll rightfully complain:
wtf is this {"city":"Barcelona"} crap we loaded? It's not code. I can't compute!
The old JSONP hack
If only we could make plain text somehow runnable, we could grab it on runtime. We need anotherweb.com to send it as it if were code, so when it's downloaded the browser will run it. We just 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, our function is called and we get to use the data.
For 1) if the foreign server is JSONP friendly we'll ask for the data like this:
<script src="https://anotherweb.com/api/tourism-data.json?myCallback=tourismJSONP"></script>
So we'll receive it like this:
tourismJSONP({"city":"Barcelona"})
which now makes it JS code that we could interact with.
As per 2), we need to write a function with the same name in our code, like this:
function tourismJSONP(data){
alert(data.city); // "Barcelona"
}
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.
origin is defined by 3 things: protocol, port, and host. So, https://web.com is a different origin than http://web.com (different protocol), also https://web.com:8081 (different port) and obviously https://thatotherweb.net (different host)
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.
JSONP is a great away to get around cross-domain scripting errors. You can consume a JSONP service purely with JS without having to implement a AJAX proxy on the server side.
You can use the b1t.co service to see how it works. This is a free JSONP service that alllows you to minify your URLs. Here is the url to use for the service:
http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]
For example the call, http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com
would return
whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});
And thus when that get's loaded in your js as a src, it will automatically run whateverJavascriptName which you should implement as your callback function:
function minifyResultsCallBack(data)
{
document.getElementById("results").innerHTML = JSON.stringify(data);
}
To actually make the JSONP call, you can do it about several ways (including using jQuery) but here is a pure JS example:
function minify(urlToMinify)
{
url = escape(urlToMinify);
var s = document.createElement('script');
s.id = 'dynScript';
s.type='text/javascript';
s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
document.getElementsByTagName('head')[0].appendChild(s);
}
A step by step example and a jsonp web service to practice on is available at: this post
A simple example for the usage of JSONP.
client.html
<html>
<head>
</head>
body>
<input type="button" id="001" onclick=gO("getCompany") value="Company" />
<input type="button" id="002" onclick=gO("getPosition") value="Position"/>
<h3>
<div id="101">
</div>
</h3>
<script type="text/javascript">
var elem=document.getElementById("101");
function gO(callback){
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://localhost/test/server.php?callback='+callback;
elem.appendChild(script);
elem.removeChild(script);
}
function getCompany(data){
var message="The company you work for is "+data.company +"<img src='"+data.image+"'/ >";
elem.innerHTML=message;
}
function getPosition(data){
var message="The position you are offered is "+data.position;
elem.innerHTML=message;
}
</script>
</body>
</html>
server.php
<?php
$callback=$_GET["callback"];
echo $callback;
if($callback=='getCompany')
$response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";
else
$response="({\"position\":\"Development Intern\"})";
echo $response;
?>
Before understanding JSONP, you need to know JSON format and XML. Currently the most frequently used data format on the web is XML, but XML is very complicated. It makes users inconvenient to process embedded in Web pages.
To make JavaScript can easily exchange data, even as the data processing program, we use the wording according to JavaScript objects and developed a simple data exchange format, which is JSON. JSON can be used as data, or as a JavaScript program.
JSON can be directly embedded in JavaScript, using them you can directly execute certain JSON program, but due to security constraints, the browser Sandbox mechanism disables cross-domain JSON code execution.
To make JSON can be passed after the execution, we developed a JSONP. JSONP bypass the security limits of the browser with JavaScript Callback functionality and the < script > tag.
So in short it explains what JSONP is, what problem it solves (when to use it).
JSONP stands for JSON with Padding.
Here is the site, with great examples, with the explanation from the simplest use of this technique to the most advanced in plane JavaScript:
w3schools.com / JSONP
One of my more favorite techniques described above is Dynamic JSON Result, which allow to send JSON to the PHP file in URL parameter, and let the PHP file also return a JSON object based on the information it gets.
Tools like jQuery also have facilities to use JSONP:
jQuery.ajax({
url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
jsonp: "callbackName",
dataType: "jsonp"
}).done(
response => console.log(response)
);
Background
You should look to use CORS where possible (i.e. your server or
API supports it, and the browser support is adequate), as JSONP has inherent security risks.
Examples
JSONP (JSON with Padding) is a method commonly used to
bypass the cross-domain policies in web browsers. (You are not allowed to make AJAX requests to a web page perceived to be on a different server by the browser.)
JSON and JSONP behave differently on the client and the server. JSONP requests are not dispatched using the XMLHTTPRequest and the associated browser methods. Instead, a <script> tag is created, whose source is set to the target URL. This script tag is then added to the DOM (normally inside the <head> element).
JSON Request:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP Request:
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
The difference between a JSON response and a JSONP response is that the JSONP response object is passed as an argument to a callback function.
JSON:
{ "bar": "baz" }
JSONP:
foo( { "bar": "baz" } );
This is why you see JSONP requests containing the callback parameter so that the server knows the name of the function to wrap the response.
This function must exist in the global scope at the time the <script> tag is evaluated by the browser (once the request has been completed).
Another difference to be aware of between the handling of a JSON response and a JSONP response is that any parse errors in a JSON response could be caught by wrapping the attempt to evaluate the responseText
in a try/catch statement. Because of the nature of a JSONP response, parse errors in the response will cause an uncatchable JavaScript parse error.
Both formats can implement timeout errors by setting a timeout before initiating the request and clearing the timeout in the response handler.
Using jQuery
The usefulness of using jQuery to make JSONP requests, is that jQuery does all of the work for you in the background.
By default, jQuery requires you to include &callback=? in the URL of your AJAX request. jQuery will take the success function you specify, assign it a unique name, and publish it in the global scope. It will then replace the question mark ? in &callback=? with the name it has assigned.
Comparing similar JSON and JSONP Implementations
The following assumes a response object { "bar" : "baz" }
JSON:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP:
function foo(response) {
document.getElementById("output").innerHTML = response.bar;
};
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
I understand JSON, but not JSONP. Wikipedia's document on JSON is (was) the top search result for JSONP. It says this:
JSONP or "JSON with padding" is a JSON extension wherein a prefix is specified as an input argument of the call itself.
Huh? What call? That doesn't make any sense to me. JSON is a data format. There's no call.
The 2nd search result is from some guy named Remy, who writes this about JSONP:
JSONP is script tag injection, passing the response from the server in to a user specified function.
I can sort of understand that, but it's still not making any sense.
So what is JSONP? Why was it created (what problem does it solve)? And why would I use it?
Addendum: I've just created a new page for JSONP on Wikipedia; it now has a clear and thorough description of JSONP, based on jvenema's answer.
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.
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”.)
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 . ")";
?>
This is my ELI5 (explain me like I'm 5) attempt for those that need it.
TL;DR
JSONP is an old trick invented to bypass the security restriction in web browsers that forbids us to get data that is in a different website/server (called different origin1) than our own.
The trick works by using a <script> tag to load a JSON (e.g.: { "city":"Barcelona" }) from somewhere else, that will send us the data wrapped in a function, the actual JSONP ("JSON with Padding"):
tourismJSONP({"city":"Barcelona"})
Receiving it in this way enables us to use the data within our tourismJSONP function. JSONP is a bad practice and not needed anymore, don't use it (read at the end).
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:
This is a Content Security Policy restriction error, it's designed to protect users from certain attacks. You should just configure it properly (see at the end).
How would the JSONP trick help us here? 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.
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 is not code. There's nothing to run; it's just plain text.
Hence, the browser will download the data pointed at by our <script> tag and when processing it'll rightfully complain:
wtf is this {"city":"Barcelona"} crap we loaded? It's not code. I can't compute!
The old JSONP hack
If only we could make plain text somehow runnable, we could grab it on runtime. We need anotherweb.com to send it as it if were code, so when it's downloaded the browser will run it. We just 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, our function is called and we get to use the data.
For 1) if the foreign server is JSONP friendly we'll ask for the data like this:
<script src="https://anotherweb.com/api/tourism-data.json?myCallback=tourismJSONP"></script>
So we'll receive it like this:
tourismJSONP({"city":"Barcelona"})
which now makes it JS code that we could interact with.
As per 2), we need to write a function with the same name in our code, like this:
function tourismJSONP(data){
alert(data.city); // "Barcelona"
}
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.
origin is defined by 3 things: protocol, port, and host. So, https://web.com is a different origin than http://web.com (different protocol), also https://web.com:8081 (different port) and obviously https://thatotherweb.net (different host)
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.
JSONP is a great away to get around cross-domain scripting errors. You can consume a JSONP service purely with JS without having to implement a AJAX proxy on the server side.
You can use the b1t.co service to see how it works. This is a free JSONP service that alllows you to minify your URLs. Here is the url to use for the service:
http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]
For example the call, http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com
would return
whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});
And thus when that get's loaded in your js as a src, it will automatically run whateverJavascriptName which you should implement as your callback function:
function minifyResultsCallBack(data)
{
document.getElementById("results").innerHTML = JSON.stringify(data);
}
To actually make the JSONP call, you can do it about several ways (including using jQuery) but here is a pure JS example:
function minify(urlToMinify)
{
url = escape(urlToMinify);
var s = document.createElement('script');
s.id = 'dynScript';
s.type='text/javascript';
s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
document.getElementsByTagName('head')[0].appendChild(s);
}
A step by step example and a jsonp web service to practice on is available at: this post
A simple example for the usage of JSONP.
client.html
<html>
<head>
</head>
body>
<input type="button" id="001" onclick=gO("getCompany") value="Company" />
<input type="button" id="002" onclick=gO("getPosition") value="Position"/>
<h3>
<div id="101">
</div>
</h3>
<script type="text/javascript">
var elem=document.getElementById("101");
function gO(callback){
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://localhost/test/server.php?callback='+callback;
elem.appendChild(script);
elem.removeChild(script);
}
function getCompany(data){
var message="The company you work for is "+data.company +"<img src='"+data.image+"'/ >";
elem.innerHTML=message;
}
function getPosition(data){
var message="The position you are offered is "+data.position;
elem.innerHTML=message;
}
</script>
</body>
</html>
server.php
<?php
$callback=$_GET["callback"];
echo $callback;
if($callback=='getCompany')
$response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";
else
$response="({\"position\":\"Development Intern\"})";
echo $response;
?>
Before understanding JSONP, you need to know JSON format and XML. Currently the most frequently used data format on the web is XML, but XML is very complicated. It makes users inconvenient to process embedded in Web pages.
To make JavaScript can easily exchange data, even as the data processing program, we use the wording according to JavaScript objects and developed a simple data exchange format, which is JSON. JSON can be used as data, or as a JavaScript program.
JSON can be directly embedded in JavaScript, using them you can directly execute certain JSON program, but due to security constraints, the browser Sandbox mechanism disables cross-domain JSON code execution.
To make JSON can be passed after the execution, we developed a JSONP. JSONP bypass the security limits of the browser with JavaScript Callback functionality and the < script > tag.
So in short it explains what JSONP is, what problem it solves (when to use it).
JSONP stands for JSON with Padding.
Here is the site, with great examples, with the explanation from the simplest use of this technique to the most advanced in plane JavaScript:
w3schools.com / JSONP
One of my more favorite techniques described above is Dynamic JSON Result, which allow to send JSON to the PHP file in URL parameter, and let the PHP file also return a JSON object based on the information it gets.
Tools like jQuery also have facilities to use JSONP:
jQuery.ajax({
url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
jsonp: "callbackName",
dataType: "jsonp"
}).done(
response => console.log(response)
);
Background
You should look to use CORS where possible (i.e. your server or
API supports it, and the browser support is adequate), as JSONP has inherent security risks.
Examples
JSONP (JSON with Padding) is a method commonly used to
bypass the cross-domain policies in web browsers. (You are not allowed to make AJAX requests to a web page perceived to be on a different server by the browser.)
JSON and JSONP behave differently on the client and the server. JSONP requests are not dispatched using the XMLHTTPRequest and the associated browser methods. Instead, a <script> tag is created, whose source is set to the target URL. This script tag is then added to the DOM (normally inside the <head> element).
JSON Request:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP Request:
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
The difference between a JSON response and a JSONP response is that the JSONP response object is passed as an argument to a callback function.
JSON:
{ "bar": "baz" }
JSONP:
foo( { "bar": "baz" } );
This is why you see JSONP requests containing the callback parameter so that the server knows the name of the function to wrap the response.
This function must exist in the global scope at the time the <script> tag is evaluated by the browser (once the request has been completed).
Another difference to be aware of between the handling of a JSON response and a JSONP response is that any parse errors in a JSON response could be caught by wrapping the attempt to evaluate the responseText
in a try/catch statement. Because of the nature of a JSONP response, parse errors in the response will cause an uncatchable JavaScript parse error.
Both formats can implement timeout errors by setting a timeout before initiating the request and clearing the timeout in the response handler.
Using jQuery
The usefulness of using jQuery to make JSONP requests, is that jQuery does all of the work for you in the background.
By default, jQuery requires you to include &callback=? in the URL of your AJAX request. jQuery will take the success function you specify, assign it a unique name, and publish it in the global scope. It will then replace the question mark ? in &callback=? with the name it has assigned.
Comparing similar JSON and JSONP Implementations
The following assumes a response object { "bar" : "baz" }
JSON:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP:
function foo(response) {
document.getElementById("output").innerHTML = response.bar;
};
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
I understand JSON, but not JSONP. Wikipedia's document on JSON is (was) the top search result for JSONP. It says this:
JSONP or "JSON with padding" is a JSON extension wherein a prefix is specified as an input argument of the call itself.
Huh? What call? That doesn't make any sense to me. JSON is a data format. There's no call.
The 2nd search result is from some guy named Remy, who writes this about JSONP:
JSONP is script tag injection, passing the response from the server in to a user specified function.
I can sort of understand that, but it's still not making any sense.
So what is JSONP? Why was it created (what problem does it solve)? And why would I use it?
Addendum: I've just created a new page for JSONP on Wikipedia; it now has a clear and thorough description of JSONP, based on jvenema's answer.
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.
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”.)
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 . ")";
?>
This is my ELI5 (explain me like I'm 5) attempt for those that need it.
TL;DR
JSONP is an old trick invented to bypass the security restriction in web browsers that forbids us to get data that is in a different website/server (called different origin1) than our own.
The trick works by using a <script> tag to load a JSON (e.g.: { "city":"Barcelona" }) from somewhere else, that will send us the data wrapped in a function, the actual JSONP ("JSON with Padding"):
tourismJSONP({"city":"Barcelona"})
Receiving it in this way enables us to use the data within our tourismJSONP function. JSONP is a bad practice and not needed anymore, don't use it (read at the end).
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:
This is a Content Security Policy restriction error, it's designed to protect users from certain attacks. You should just configure it properly (see at the end).
How would the JSONP trick help us here? 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.
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 is not code. There's nothing to run; it's just plain text.
Hence, the browser will download the data pointed at by our <script> tag and when processing it'll rightfully complain:
wtf is this {"city":"Barcelona"} crap we loaded? It's not code. I can't compute!
The old JSONP hack
If only we could make plain text somehow runnable, we could grab it on runtime. We need anotherweb.com to send it as it if were code, so when it's downloaded the browser will run it. We just 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, our function is called and we get to use the data.
For 1) if the foreign server is JSONP friendly we'll ask for the data like this:
<script src="https://anotherweb.com/api/tourism-data.json?myCallback=tourismJSONP"></script>
So we'll receive it like this:
tourismJSONP({"city":"Barcelona"})
which now makes it JS code that we could interact with.
As per 2), we need to write a function with the same name in our code, like this:
function tourismJSONP(data){
alert(data.city); // "Barcelona"
}
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.
origin is defined by 3 things: protocol, port, and host. So, https://web.com is a different origin than http://web.com (different protocol), also https://web.com:8081 (different port) and obviously https://thatotherweb.net (different host)
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.
JSONP is a great away to get around cross-domain scripting errors. You can consume a JSONP service purely with JS without having to implement a AJAX proxy on the server side.
You can use the b1t.co service to see how it works. This is a free JSONP service that alllows you to minify your URLs. Here is the url to use for the service:
http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]
For example the call, http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com
would return
whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});
And thus when that get's loaded in your js as a src, it will automatically run whateverJavascriptName which you should implement as your callback function:
function minifyResultsCallBack(data)
{
document.getElementById("results").innerHTML = JSON.stringify(data);
}
To actually make the JSONP call, you can do it about several ways (including using jQuery) but here is a pure JS example:
function minify(urlToMinify)
{
url = escape(urlToMinify);
var s = document.createElement('script');
s.id = 'dynScript';
s.type='text/javascript';
s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
document.getElementsByTagName('head')[0].appendChild(s);
}
A step by step example and a jsonp web service to practice on is available at: this post
A simple example for the usage of JSONP.
client.html
<html>
<head>
</head>
body>
<input type="button" id="001" onclick=gO("getCompany") value="Company" />
<input type="button" id="002" onclick=gO("getPosition") value="Position"/>
<h3>
<div id="101">
</div>
</h3>
<script type="text/javascript">
var elem=document.getElementById("101");
function gO(callback){
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://localhost/test/server.php?callback='+callback;
elem.appendChild(script);
elem.removeChild(script);
}
function getCompany(data){
var message="The company you work for is "+data.company +"<img src='"+data.image+"'/ >";
elem.innerHTML=message;
}
function getPosition(data){
var message="The position you are offered is "+data.position;
elem.innerHTML=message;
}
</script>
</body>
</html>
server.php
<?php
$callback=$_GET["callback"];
echo $callback;
if($callback=='getCompany')
$response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";
else
$response="({\"position\":\"Development Intern\"})";
echo $response;
?>
Before understanding JSONP, you need to know JSON format and XML. Currently the most frequently used data format on the web is XML, but XML is very complicated. It makes users inconvenient to process embedded in Web pages.
To make JavaScript can easily exchange data, even as the data processing program, we use the wording according to JavaScript objects and developed a simple data exchange format, which is JSON. JSON can be used as data, or as a JavaScript program.
JSON can be directly embedded in JavaScript, using them you can directly execute certain JSON program, but due to security constraints, the browser Sandbox mechanism disables cross-domain JSON code execution.
To make JSON can be passed after the execution, we developed a JSONP. JSONP bypass the security limits of the browser with JavaScript Callback functionality and the < script > tag.
So in short it explains what JSONP is, what problem it solves (when to use it).
JSONP stands for JSON with Padding.
Here is the site, with great examples, with the explanation from the simplest use of this technique to the most advanced in plane JavaScript:
w3schools.com / JSONP
One of my more favorite techniques described above is Dynamic JSON Result, which allow to send JSON to the PHP file in URL parameter, and let the PHP file also return a JSON object based on the information it gets.
Tools like jQuery also have facilities to use JSONP:
jQuery.ajax({
url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
jsonp: "callbackName",
dataType: "jsonp"
}).done(
response => console.log(response)
);
Background
You should look to use CORS where possible (i.e. your server or
API supports it, and the browser support is adequate), as JSONP has inherent security risks.
Examples
JSONP (JSON with Padding) is a method commonly used to
bypass the cross-domain policies in web browsers. (You are not allowed to make AJAX requests to a web page perceived to be on a different server by the browser.)
JSON and JSONP behave differently on the client and the server. JSONP requests are not dispatched using the XMLHTTPRequest and the associated browser methods. Instead, a <script> tag is created, whose source is set to the target URL. This script tag is then added to the DOM (normally inside the <head> element).
JSON Request:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP Request:
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
The difference between a JSON response and a JSONP response is that the JSONP response object is passed as an argument to a callback function.
JSON:
{ "bar": "baz" }
JSONP:
foo( { "bar": "baz" } );
This is why you see JSONP requests containing the callback parameter so that the server knows the name of the function to wrap the response.
This function must exist in the global scope at the time the <script> tag is evaluated by the browser (once the request has been completed).
Another difference to be aware of between the handling of a JSON response and a JSONP response is that any parse errors in a JSON response could be caught by wrapping the attempt to evaluate the responseText
in a try/catch statement. Because of the nature of a JSONP response, parse errors in the response will cause an uncatchable JavaScript parse error.
Both formats can implement timeout errors by setting a timeout before initiating the request and clearing the timeout in the response handler.
Using jQuery
The usefulness of using jQuery to make JSONP requests, is that jQuery does all of the work for you in the background.
By default, jQuery requires you to include &callback=? in the URL of your AJAX request. jQuery will take the success function you specify, assign it a unique name, and publish it in the global scope. It will then replace the question mark ? in &callback=? with the name it has assigned.
Comparing similar JSON and JSONP Implementations
The following assumes a response object { "bar" : "baz" }
JSON:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
JSONP:
function foo(response) {
document.getElementById("output").innerHTML = response.bar;
};
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
Question
I need to parse an RSS feed and display the parsed details in an HTML page.
Solution I Found
How to parse an RSS feed using JavaScript? is a very similar question and I followed it.
Using above question, I build the following code.
<script>
$(document).ready(function() {
//feed to parse
var feed = "https://feeds.feedburner.com/raymondcamdensblog?format=xml";
$.ajax(feed, {
accepts:{
xml:"application/rss+xml"
},
dataType:"xml",
success:function(data) {
//Credit: http://stackoverflow.com/questions/10943544/how-to-parse-an-rss-feed-using-javascript
$(data).find("item").each(function () { // or "item" or whatever suits your feed
var el = $(this);
document.write("------------------------");
document.write("title : " + el.find("title").text());
document.write("link : " + el.find("link").text());
document.write("description: " + el.find("description").text());
});
}
});
});
</script>
The Error
Failed to load
https://feeds.feedburner.com/raymondcamdensblog?format=xml: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost' is therefore not allowed access.
What I need
How can I change my code to read RSS feeds using JavaScript without getting above error?
You could use something like https://rss2json.com.
It parses the feed to json for javascript:
var feedURL = "https://feeds.feedburner.com/raymondcamdensblog?format=xml";
$.ajax({
type: 'GET',
url: "https://api.rss2json.com/v1/api.json?rss_url=" + feedURL,
dataType: 'jsonp',
success: function(result) {
console.log(result);
}
});
You're getting that error because of the same-origin policy. See below and/or read the full article at MDN:
For security reasons, browsers restrict cross-origin HTTP requests
initiated from within scripts. For example, XMLHttpRequest and the
Fetch API follow the same-origin policy. This means that a web
application using those APIs can only request HTTP resources from the
same origin the application was loaded from, unless the response
from the other origin includes the right CORS headers.
So your script is making a cross-origin HTTP request (which uses XMLHttpRequest through jQuery.ajax()) to https://feeds.feedburner.com/raymondcamdensblog?format=xml, but the CORS header of Access-Control-Allow-Origin is not being set by FeedBurner, therefore you get the "Failed to load ..." error. (But even if the header was set, if it didn't include your origin (localhost or some-domain.com), you'd still get the same error.)
So how can you change your code to read the RSS feeds using JavaScript without getting that error?
Use a third-party web service, just like what #Saeed suggested.
Create a server-side script (e.g. using PHP) that fetches the feed content and make AJAX requests to that script instead of directly requesting it from FeedBurner, or the actual source URL. See below for a simple example.
If I really had to, I'd probably ask FeedBurner to set the appropriate CORS headers...
Sample of a very simple PHP script for fetching the feed content:
<?php
// Set the feed URL.
$feed_url = 'https://feeds.feedburner.com/raymondcamdensblog?format=xml';
// Fetch the content.
// See http://php.net/manual/en/function.file-get-contents.php for more
// information about the file_get_contents() function.
$content = file_get_contents( $feed_url );
// Set the Content-Type header.
header( 'Content-Type: application/rss+xml' );
// Display the content and exit.
echo $content;
exit;
?>
So for example, you could save that to fetch-feed.php, and then in your JavaScript/jQuery script code, change the value of the feed variable like so:
var feed = "http://localhost/path/to/fetch-feed.php";
That way (i.e. using your own server-side script), you could at least be sure that the browser would always grant your XMLHttpRequest (or AJAX) request. (i.e. you wouldn't get the "No 'Access-Control-Allow-Origin' header" error)
You can also use jquery-rss or Vanilla RSS, which comes with nice templating and is super easy to use:
// Example for jquery.rss
$("#your-div").rss("https://feeds.feedburner.com/raymondcamdensblog?format=xml", {
limit: 3,
layoutTemplate: '<ul class="inline">{entries}</ul>',
entryTemplate: '<li>[{author}#{date}] {title}<br/>{shortBodyPlain}</li>'
})
// Example for Vanilla RSS
const RSS = require('vanilla-rss');
const rss = new RSS(
document.querySelector("#your-div"),
"https://feeds.feedburner.com/raymondcamdensblog?format=xml",
{
// options go here
}
);
rss.render().then(() => {
console.log('Everything is loaded and rendered');
});
See http://jsfiddle.net/sdepold/ozq2dn9e/1/ for a working example.
It's a CORS related error. You are getting that error because the URL from where you are requesting data does not have CORS enabled. CORS stands for 'Cross-Origin Resource Sharing'. If CORS is enabled on a server, your browser will let you make requests to that server. Otherwise, it will not.
https://feeds.feedburner.com/raymondcamdensblog?format=xml does not have CORS enabled, that's why your browser will not allow you to make ajax requests to that server. You can get around it by making the requests on your server and provide the data to the browser from your own server or a server that has CORS enabled.
I was trying to perform client side validation for captcha. For that I need to get the response from an external url. I used the below javascript code for that.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript">
function captcha_check()
{
var code = document.getElementById("captcha").value;
alert(code);
var url = "http://www.opencaptcha.com/validate.php?img='.$captcha_name.'.jpgx&ans="+code;
alert(url);
$.get(url,function(data,status){
alert(data);
if(data == "fail")
{
document.getElementById("captcha_error").style.display = "block";
return false;
}
else
{
return true;
}
});
}
</script>
But the code is not working. The url and code are alerting correctly. But the javascript stops executing the jquery function to get content from the url and skipping the remaining steps in the function.
Please help me find out what's wrong with my code.
Thank you all in advance.
Cross domain ajax request can't be done unless the response accept request from all domains.
Also i don't think client side validation for captcha can be called "secure".
More info:
Cross-Origin Resource Sharing (CORS)
There are security restrictions on cross domain ajax calls.
Check out http://en.wikipedia.org/wiki/Same_origin_policy
I tried a your code from my location and chrome returns:
XMLHttpRequest cannot load http://www.opencaptcha.com/validate.php?img=%27.$captcha_name.%27.jpgx&ans=hi. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access.
which is what you expect with cross domain calls like this.
This is why your code is failing.