杰拉斯的博客

jQuery中利用JSONP解决AJAX跨域问题

杰拉斯 杰拉斯 | 时间:2012-08-10, Fri | 172,143 views
前端开发 

写在前面

跨域的解决方案有多种,其中最常见的是使用同一服务器下的代理来获取远端数据,再通过ajax进行读取,而在这期间经过了两次请求过程,使得获取数据的效率大大降低,这篇文章蓝飞就为大家介绍一下解决跨域问题的一种比较通用的方案——JSONP。

什么是跨域?

简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即“同源策略”。而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果。

具体策略限制情况可看下表:

URL 说明 允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议 不允许
http://www.a.com/a.js
http://127.0.0.100/b.js
域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上) 不允许
http://www.a.com/a.js
http://www.b.com/b.js
不同域名 不允许

什么是JSONP?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,而JSONP(JSON with Padding)则是JSON 的一种“使用模式”,通过这种模式可以实现数据的跨域获取。

JSONP跨域的原理

在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img、iframe、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。利用script标签的开放策略,我们可以实现跨域请求数据,当然,也需要服务端的配合。当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据,而我们使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码。

举个例子,假如需要从服务器(http://www.a.com/user?id=123)获取的数据如下:

{"id": 123, "name" : "张三", "age": 17}

那么,使用JSONP方式请求(http://www.a.com/user?id=123?callback=foo)的数据将会是如下:

foo({"id": 123, "name" : "张三", "age": 17});

当然,如果服务端考虑得更加充分,返回的数据可能如下:

try{foo({"id": 123, "name" : "张三", "age": 17});}catch(e){}

PHP为例,服务端的代码应该如下:

$json = json_encode(array("id" => 123, "name" => "张三", "age" => 17));
if(isset($_GET['callback'])){
	$json = 'try{' . $_GET['callback'] . '(' . $json . ')}catch(e){}';
}
echo $json;

这时候我们只要定义一个foo()函数,并动态地创建一个script标签,使其的src属性为http://www.a.com/user?id=123?callback=foo:

<script type="text/javascript" src="http://www.a.com/user?id=123?callback=foo"></script>

便可以使用foo函数来调用返回的数据了。

jQuery中如何通过JSONP来跨域获取数据

第一种方法是在ajax函数中设置dataType为'jsonp':

$.ajax({
	dataType: 'jsonp',
	url: 'http://www.a.com/user?id=123',
	success: function(data){
		//处理data数据
	}
});

第二种方法是利用getJSON来实现,只要在地址中加上callback=?参数即可:

$.getJSON('http://www.a.com/user?id=123&callback=?', function(data){
	//处理data数据
});

也可以简单地使用getScript方法:

//此时也可以在函数外定义foo方法
function foo(data){
	//处理data数据
}
$.getScript('http://www.a.com/user?id=123&callback=foo');

JSONP的应用

JSONP在开放API中可以起到非常重要的作用,开放API一般是运用于开发者的应用上,而这些应用往往是在开发者的服务器上而并非在新浪微博的服务器上,因此跨域请求数据成为前端开发者们所需要解决的一大问题,广大开放平台应该实现对JSONP的支持,这一点新浪微博开放平台便做的非常好(虽然某些API里没有说明,但实际上是可以使用JSONP方式调用的)。

如需转载请注明出处:杰拉斯的博客

相关文章

25 条评论 »

  1. hP hP

    ajax做得很好啊!背景的话,如果是仿ios界面,应该是不动的吧。

    1. 背景= =?
      我这倒是没模仿IOS的哦,自己随便弄的= =。。

      1. hP hP

        啊。。我说左边导航栏的 织纹背景

        1. 的确是不动的呀,如果是在支持position:fixed的浏览器下的话。

      2. 做的不错啊

  2. 请问你的这个代码高亮显示的插件是什么?怎么配置的?

    1. @麦田麦穗
      Google Code Prettify

  3. hah hah

    第二种方法应该加 ?callback=?

  4. simpleDean simpleDean

    请问服务端的代码应该如何编写呢?

    1. 判断是否有callback参数,若有,则加上函数调用代码。
      详见上文『以PHP为例,服务端的代码应该如下』部分。

      1. wpw wpw

        在 在jQuery中如何通过JSONP来跨域获取数据 中的三种方式中
        不论是哪种,前台都需要写后台返回的处理函数吧。

  5. hudonghuicom hudonghuicom

    http://android.fengjing.com/201308/json/ThreamList.aspx?ctId=1&ttId=2&curpage=1&pagesize=10比如这样一个数据我怎么调取json,,再如这个内网的 http://192.168.13.62:86/am/touristMap.aspx?scenicId=11685怎么弄

    1. 纯前端的话需要该接口支持JSONP,否则就用PHP之类的进行代理。

  6. julie julie

    写的很详细,很有帮助啊

  7. 和返回
    var foo = {"id": 123, "name" : "张三", "age": 17};
    对比该怎么理解呢?同步和异步的差别?
    然后这主题是自己弄的么?好想扒。。

    1. 跟 JSONP 对比吗?
      JSONP 是可以直接调起回调函数,如果只是赋值的话还需要去检测 script 标签的加载状态,这又要引入不少问题了。
      主题是自己弄的,其实已经想换掉它很久了。。

  8. 匿名 匿名

    我用$.getJSON(),无法获取回调返回的数据,没能想明白,Google了,也没能解决

    1. 是跨域么?对应的地址是JSONP么?

  9. [...]参考 jQuery中利用JSONP解决AJAX跨域问题 http://www.clanfei.com/2012/08/1637.html[...]

  10. [...]jQuery中利用JSONP解决AJAX跨域问题[...]

  11. jsonp跨域调用蛮方便的

  12. [...]=======================签 名 档=======================原文地址(我的博客):http://www.clanfei.com/2012/08/1637.html欢迎访问交流,至于我为什么要多弄一个博客,因为我热爱前端,热爱网页,我更希望有一个更加自由、真正属于我自己的小站,或许并不是那么有名气,但至少能够让我为了它而加倍努力。。=============[...]

  13. mager mager

    请问可以给一个详细的例子吗?包括前端和服务器端(php)的写法,你说的:详见上文『以PHP为例,服务端的代码应该如下』部分。,没有看到呢。

  14. 咦,没有吗?我这看得到呀