JSONP原理与使用
http://www.ibm.com/developerworks/library/wa-aj-jsonp1/
AJAX可以用来在后台获取数据,而不干扰前台的web显示。它通过使用XMLHttpRequest来使得客户端的JavaScript可以与服务器建立http连接。但是根据同源策略,这种方法不能获取跨域名的数据,如果尝试从一个不同的域名下请求数据,将会返回一个安全错误。同源策略禁止一个脚本从一个域获取或操作另一个域上的文档,即请求的URL必须是与当前的页面同域名的。这项浏览器的策略可以追溯到Netscape Navigator 2.0.
一个相对简单的方法是当前页面所在的服务器作为一个代理中继,该页面向自己的服务器请求数据,而服务器再向第三方的服务器请求需要的数据。另一种方法是使用框架元素在当前页面中创建新的areas,然后利用GET请求获取需要的第三方数据,在Frame中的数据内容就符合同源策略。
更有效的方法是在页面中插入一个动态的script元素。该script的src指向第三方域的URL,并在sript中返回需要的数据。一旦脚本文件被加载,它就会被执行。
JSON是一个轻量级的数据格式用来在浏览器和服务器之间交换数据。JSON实际上是用字符串string来表示一个JavaScript对象。例如有一个股票对象,它有两个属性符号和价格。在JavaScript中采用如下的方法来定义这个对象:
var ticker = {symbol: 'IBM', price: 91.42};
使用JSON表示这个对象如下:
{symbol: 'IBM', price: 91.42}
定义一个函数来显示股票价格:
function showPrice(data) {
alert("Symbol: " + data.symbol + ", Price: " +data.price);
}
通过向这个函数传递JSON数据作为参数:
showPrice({symbol: 'IBM', price: 91.42});// alerts: Symbol: IBM, Price: 91.42
当把这两段代码放入同一个页面中后:
<scripttype="text/javascript">
function showPrice(data) {
alert("Symbol: " + data.symbol + ", Price: " +data.price);
}
</script>
<scripttype="text/javascript">showPrice({symbol: 'IBM', price:91.42});</script>
当页面加载完毕将会有提示信息。
下面开始使用动态JavaScript插入的方法
将
showPrice({symbol: 'IBM', price: 91.42});// alerts: Symbol: IBM, Price: 91.42
存入一个单独的JavaScript文件中,如help.js。
在一个页面中加入如下代码:
<scripttype="text/javascript">
// This is ourfunction to be called with JSON data
function showPrice(data){
alert("Symbol: " + data.symbol +", Price: " + data.price);
}
var url = “help.js”;// URL of the external script
// this showsdynamic script insertion
var script =document.createElement('script');
script.setAttribute('src',url);
// load the script
document.getElementsByTagName('head')[0].appendChild(script);
</script>
在页面中动态插入help.js后,将会自动执行其中的JavaScript代码,使用实际的help.js文件中返回的数据作为参数来调用showPrice()函数。
由于同源策略不阻止动态插入script元素,所以就可以在页面中以插入不同域的带有JSON数据的JavaScript程序。JSONP(JSON with Padding):JSON data wrapped in a function call. 需要注意的是,在页面中必须在插入JavaScript代码前预先定义好回调函数,并在回调函数中对得到的JSON数据进行处理,例如此处的showPrice()。
JSONP服务就是指服务器支持将返回的JSON数据封装到涌入自定义的函数调用中的服务。这种方法依赖于远程服务接收一个回调函数名作为参数,服务器产生一个该函数的调用,并将返回的JSON数据作为它的参数,当到大客户端时,这个函数就会被执行。
JQuery 的JSONP支持
JQuery从1.2版本开始原生的支持JSONP调用。如果按照url?callback=?的语法指定一个JSONP回调函数,就可以加载一个跨域的JSON数据。JQuery可以自动的将?替换为一个生成的函数名的调用。
jQuery.getJSON(url+"&callback=?", function(data) { alert("Symbol: " + data.symbol + ", Price: " + data.price);});JQuery向window对象添加了一个全局函数,这个函数在脚本被插入后就被调用。当完成后,这个函数就被删除。同时JQuery还对非跨域的调用进行优化,如果是在同一个域名下,就会使用普通的AJAX请求。
JSONP服务举例:
首先假设服务器在URL请求中接受一个参数名为callback,同时假设对JSONP服务的请求如下:
http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=showPricesymbol是一个表示股票代码的请求参数,callback参数指出了客户端页面中回调函数的名字。在JQuery中可以采用如下的方式发送请求。
jQuery.getJSON("http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=?", function(data) { alert("Symbol: " + data.symbol + ", Price: " + data.price);});在这里使用?作为回调函数的名称,而不是实际定义的回调函数名。因为JQuery会自动将?替换为一个函数名(如 jsonp1232617941775),该函数会调用其中的内联函数。这样用户不用在定义具体的函数如showPrice()函数。
下面的代码说明如何使用PHP实现JSONP服务:
$jsonData = getDataAsJson($_GET['symbol']);echo $_GET['callback'] . '(' . $jsonData . ');';// prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});下面的代码说明如何使用Java实现JSONP服务:
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String jsonData = getDataAsJson(req.getParameter("symbol")); String output = req.getParameter("callback") + "(" + jsonData + ");"; resp.setContentType("text/javascript"); PrintWriter out = resp.getWriter(); out.println(output); // prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});}
mashup是糅合,是当今网络上新出现的一种网络现象,将两种以上使用公共或者私有数据库的web应用,加在一起,形成一个整合应用。 现在假如你是一个Web开发者,你通过一个API 找到你附近哪些地方会有犯罪。然后你访问Google 地图API,把这两个内容整合在一起,那么你就得到了一个标有犯罪纪录的地图。这个新的地图就叫Mashup。因为开发者通过来自多个网站的APIs,把他们合并在一起,成为了一个新的很cool的应用程序。
豆瓣网的JavaScript客户端实现:
http://www.douban.com/js/api.js?v=2
一个简单的JSONP封装:
functionload_script(url, callback) {
// 获取head标签
var head =document.getElementsByTagName('head')[0];
// 创建script标签
var script =document.createElement('script');
// 指定script类型
script.type = 'text/javascript';
// 需要ajax调用的url
script.src = url;
// 借鉴了jQuery的script跨域方法
//侦听script的onload、onreadystatechange事件,并执行回调函数(取数据、处理数据的操作)
script.onload = script.onreadystatechange= function() {
if ((!this.readyState ||this.readyState === "loaded" || this.readyState ==="complete")) {
//调用回调函数,这样写的好处是:如果回调函数不存在,不会抛异常
callback &&callback();
// Handle memory leak in IE
script.onload =script.onreadystatechange = null;
// 删除掉创建的script标签
if (head &&script.parentNode) {
head.removeChild(script);
}
}
};
// Use insertBefore instead ofappendChild to circumvent an IE6 bug.
// 创建script标签,发起ajax调用
head.insertBefore(script,head.firstChild);
}
//直接访问http://suggestion.baidu.com/su?wd=ww 可以看到返回的结果为:
//window.baidu.sug({q:"ww",p:true,s:["wwe","www.baidu.com","www.163.com","www.taobao.com","www.qq.co//m","www.4399.com","www.126.com","www.51.com","www.hao123.com","www.youku.com"]});
//1.假设想取的数据为sug里的s部分的数组
//2.那么在成功返回请求结果后,上面的window.baidu.sug(....)实际上就是调用了下面已经定义好的sug方法
//其中,data表示形参,对应着sug里的{q:....}部分的数据
//3.因此,通过data.s便可以获取到["wwe"...]部分的数组
//4.仅此而已...
window.baidu= {
sug : function(data) {
alert(data.s);
}
};
load_script('http://suggestion.baidu.com/su?wd=w',function() {
alert('loaded');
});
豆瓣网的JavaScript客户端实现:
http://www.douban.com/js/api.js?v=2
另一篇文章里介绍了如何使用YQL和JQuery使用JSONP的方式来获取APIs提供的数据。
http://www.ibm.com/developerworks/web/library/wa-aj-jsonp2/index.html
以下代码实现了使用YQL利用flickr的API进行图片搜索,并根据图片信息合成图片的地址。
var yqlUrl3="http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20flickr.photos.search%20where%20text%3D%22apple%22%20limit%2030&format=json&diagnostics=true&callback=?";
var count = 0;
$.getJSON(yqlUrl3, function(data){
$.each(data.query.results.photo, function(index, item){
var imgId = item.id;
var farm = item.farm;
var server = item.server;
var secret = item.secret;
var title = item.title;
var owner = item.owner;
var turl ="http://www.flickr.com/photos/"+owner + "/"+imgId;
// construct the url of the images
var imgurl = "http://farm"+farm+".static.flickr.com/"+server+"/"+imgId+"_"+secret+".jpg";
$('#weather').append(
$('<p/>').append($('<span class="img_title"/>').text(++count+"."+title).append($("<br>"))
.append($("<a href='"+turl+"' target=_blank/>")
.append($("<img src='"+imgurl+"' alt="+title+"/>")
))));
});
});
//Because the search API doesn't return the url of the images, this post introduce how to get the image's url from its information without url. http://developer.yahoo.com/blogs/ydn/posts/2010/04/building_flickr_urls_from_yql_flickrphotossearch_results/
本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

浙公网安备 33010602011771号