Making an Ajax Request to Another Domain (Using JSONP)
Problem
You want to query for data using a web service API, such as the Rotten Tomatoes API,
or the Flicker API. However, the Ajax same-origin security policy prevents cross-domain
communication
Solution
One approach is to use JSONP (JSON with padding) to work around the security issues.
First, you create a new script element, making the URL the endpoint for the API
method call. The following creates a script element with a call to Flickr’s photo search
API method:
function addScript( url) { var script = document.createElement('script'); script.type="text/javascript"; script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }
The URL looks like the following, including a request to return the data formatted as JSON, and providing a callback function name. The api_key is generated by Flickr, and the user_id is the unique user identifier, the NSID, for your account. Note this isn’t the same as the username. I’m asking for the first page of results for a given user:
http://api.flickr.com/services/rest/?method=flickr.photos.search&user_id=xxx &api_key=xxx&page=1&format=json&jsoncallback=processPhotos
When the script tag is created, the request to Flickr is made, and because I passed in the request for a JSON-formatted result and provided a callback function name, that’s how the return is provided. The following is a basic callback function that just displays the results to the console:
function processPhotos(obj) { photos = obj.photos.photo; var str = ''; photos.forEach(function(photo) { str+=photo.title + ' '; }); document.getElementById('result').innerHTML = str; }
EXPLAIN
Ajax works within a protected environment that ensures we don’t end up embedding
dangerous text or code into a web page because of a call to an external application (which
may or may not be secure).The downside to this security is that we can’t directly access
services to external APIs. Instead, we have to create a server-side proxy application
because server applications don’t face the cross-domain restriction.
One workaround is to use JSONP, demonstrated in the solution. Instead of using
XMLHttpRequest, we convert the request URL into one that we can attach to a script’s
src attribute, because the script element does not follow the same-origin policy.
If the service is amenable, it returns the data formatted as JSON, even wrapping it in a
callback function.
When the script is created, it’s no different than if the function call is
made directly in our code, and we’ve passed an object as a parameter. We don’t even
have to worry about converting the string to a JavaScript object.The callback’s argument
is a JSON object.
The photos are returned in pages, and you can repeat the calls as many times as you
want to get as many photos as you need, changing the page number with each call. contains a simple, working example of using JSONP to access information
from Flickr. Just remember to use your own API key and NSID.
Using JSONP to circumvent cross-domain restrictions and processing the result
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSONP</title> </head> <body> <div id="result"> </div> <script > function addScript( url) { var script = document.createElement('script'); script.src = url; document.getElementsByTagName('head')[0].appendChild(script); } addScript('https://api.flickr.com/services/rest/?method=flickr.photos.search &user_id=NSID&api_key=yourapikey&page=1&format=json&jsoncallback=processPhotos'); // assign photos globally, call first to load function processPhotos(obj) { photos = obj.photos.photo; var str = ''; photos.forEach(function(photo) { str+=photo.title + '<br /> '; }); document.getElementById('result').innerHTML = str; } </script> </body> </html>
It’s a clever trick, but should only be used with caution. Even with secure services such as Flickr, there is the remote possibility that someone could find a way to inject JavaScript into the data via the client-side application for the service, which can cause havoc in the application.
No comments:
Post a Comment