JSONP小结

JSONP是什么

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

由于同源策略,一般来说位于 a.com 的网页无法与不是a.com的服务器沟通,而 HTML 的<script> 元素是一个例外。

利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。


为什么需要JSONP

我们在平时的开发过程中可能遇到这种问题,某张网页的域名位于a.com,但我们需要从b.com这个url那里拉取数据。

这个时候使用Ajax是无法获取数据的,因为Ajax为了网页的安全性使用了“同源策略”。域名不同的url之间是无法使用ajax直接拉取数据的。

那么怎么办呢?


JSONP的解决方法

一、简单例子

首先我们假设服务器端有一个这样的data.js文件:

1
2
3
4
5
6
//data.js

var person = {
name : "stark" ,
sex : "male"
}

然后我们在html中引用它,同时我们再写一个handler函数:

1
2
3
4
5
6
7
8
9
<script src="data.js"></script>

<script>
function handler(data)
{
alert(data.name);
}

handler(person);//此处可以调用data.js里面的数据
</script>

注意到这里的data.js实际上可以在任意的域名下,这就意味着我们可以从任意的域名拉取data.js,实现跨域传递数据的效果。

二、改进方法

上面的方法存在局限性。

首先,data的引用是写死在页面中的。这意味着我们无法“动态”地获取数据。

其次,handler的调用也是直接写在js里面,不仅需要一个全局变量person,还需要严格地保证函数调用时数据已经data.js进来,否则会报错。

所以我们不妨这样改进一下:

首先写一个handler函数:

1
2
3
function handler(data){
alert(data.name);
}

然后拉取数据的步骤如下:

1
2
3
4
5
6
var script = document.createElement('script');

script.setAttribute('src',
'http://b.com/somePage?callback=handler&data=person');

document.getElementsByTagName('head')[0].appendChild(script);

我们在这里添加了一个<script>节点,它的url是http://b.com/somePage?callback=handler&data=person,这显然是一个get请求的url。

我们告诉服务器,回调函数为handler,我们需要的是person的数据,然后服务器返回类似这样的字符串:

1
2
3
4
handler({
name : "person" ,
sex : "male"
});

等浏览器获取到这堆字符串,便会把它当做js脚本立即执行,于是跨域获取数据就达成了。

三、jQuery的方法

上面的方法是自己从零开始写的,封装性和复用性很差,幸运的是jQuery已经为我们做好了这些东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$.ajax({
type: "get",

async: false,

url: "http://b.com/somePage?data=person",

dataType: "jsonp",

jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)

success: function(json){
alert(json.name);
},

error: function(){
alert('fail!');
}
});

这里没有写handler这个函数,而是把回调写在了success里,但也能运行成功。

这就是jQuery的功劳了,jquery在处理jsonp类型的ajax时(但其实它们真的不是一回事儿),自动生成了一个回调函数并把数据取出来供success属性方法来调用。