jsonp本身是专为跨域而诞生的。早期开发者面对跨域没什么好办法,突然有人想到,既然引入js文件是不受跨域限制的,可以随意跨域引入,那么,动态引入一个带有你想要的数据的js文件,不就实现了跨域了么?由此jsonp技术诞生。
注意,jsonp技术跟ajax没有任何关系,只不过jQuery带了一个坏的头,让人们误以为jsonp跟ajax有关。
原理
jsonp的原理简单说就是:
第一步,你的HTML中应当提前准备一个函数,比如叫ooo,大致如下,它只干一个事情,就是把json字符串转换为json对象:
function ooo(data) {
return JSON.parse(data);
}
第二步,你在你的HTML中用js拼接字符串的方式拼接一个类似于<script src="http://外域.com/xxx.php?callback=ooo"></script>
的script元素。这个http://外域.com/xxx.php?callback=ooo
的内容如下:
ooo({"name": "张学友"})
然后你需要操作DOM,把上面的<script src="http://外域.com/xxx.php?callback=ooo"></script>
插入到DOM中,这样浏览器就会把这个地址当做js文件载入,然后试图执行里面的js内容。
既然这个文件被当做js来插入DOM,那么里面所有代码都是js代码,这个ooo({"name": "张学友"})
就是js代码,浏览器会找有没有一个叫ooo的函数,显然有,我们刚才不是定义了一个ooo函数么?所以浏览器找到了这个函数,之后就执行这函数。
最后,我们就得到了一个json对象,而这个对象就是来自于外域服务器。由此,跨域达成。
没错吧,从头到尾并没有ajax什么事。
可以看出,本域跟外域沟通的桥梁,是外域的一个php文件,接头暗号就是路径里的参数callback=ooo
。也就是说,php文件要做的事情应该是:
获取callback参数的值,然后拼接一个字符串ooo({"name": "张学友"})
,其中ooo来自callback参数的值,{"name": "张学友"}是从sql中查询到的结果。
用jQuery实现jsonp的好处
然后说说jQuery的实现。jq为了让使用者更省心,当然是做了很多自动化的工作,下面都可以一一看到。主要是:
1、你不用自己写类似这样的函数,因为jQuery已经帮你写了:
function ooo(data) {
return JSON.parse(data);
}
2、你不用思考函数名用啥名,因为jQ会帮你瞎编一个函数名,通常长相是jQuery32108394227022163139_1498134481374
一大串。
jQuery中怎么实现jsonp
通常三种办法:
第一种,$.ajax()方法
当引入http://外域.com/xxx.php?callback=ooo
,php端必须让这个地址能打印出ooo({"name": "张学友"})
这样的内容,函数名ooo必须跟下面的jsonpCallback的值一致。json内容可以任意。
JS:
$.ajax({
url:'http://外域.com/xxx.php',
dataType:"jsonp",
jsonp: "callback",
jsonpCallback:"ooo",
success:function(data){
console.log(data);
}
});
这个例子里面,明确指定了jsonp: "callback"以及jsonpCallback:"ooo"。我们分别说一下:
jsonp: "callback"
是设置路径里的参数名。你这里写callback,那么jQuery发送请求的时候路径里就用callback=
jsonpCallback:"ooo"
是设置函数名。你这里写ooo,那么php必须返回ooo为函数名的内容。
这两者都可以省略,jsonp的值省略的话,缺省是callback。jsonpCallback的值省略的话,缺省是类似jsonp3731491014413739这样的'jsonp'加16位随机数。两者都省略的话,jQuery就会在路径后面接一个callback=jsonp3731491014413739这样的参数,那么,你的php就必须返回jsonp3731491014413739({"name": "张学友"})
这样的字符串。说白了,你如果js端想少写几个字,打算省掉这两个参数,那么php端就多写一些代码,需要先获取$_GET['callback']
的值,根据值拼接字符串,因此你就不可能写死函数名。
最佳实践是省掉这两个参数,不过你的php端就要对参数值做安全措施。
第二种,$.get()方法(作者推荐)
$.get()方法的基本用法是同域名抓数据,是真正的ajax原理。而高级用法就是抓jsonp数据。写法是:
$.get('http://外域.com/xxx.php', {各种数据}, function(data) {
console.log(data);
}, 'jsonp');
没有指定末尾的'jsonp'参数的时候,jQuery认为你想同域抓数据,会用xhr方法请求;只有加了参数,才认为你想抓jsonp数据。这一切由jQuery自动判断。
这个写法其实就是上面ajax写法的简化版,而且肯定设不了jsonp和jsonpCallback,所以你的php必须用类似echo $_GET['callback'].'({"name":"张学友"})';
这样的写法。假如你的路径中本来就有callback参数,而且这个callback是干别的用的,那么你就没法用$.get()方法。因为你真正的请求路径会是:http://外域/xxx.php?callback=12345678&callback=jQuery321040155744415047234_1498133674752&_=1498133674753
,看到了吧,两个callback参数,php只会认后一个,忽略前一个。
第三种:$.getJSON()方法
$.getJSON()方法跟$.get()方法类似,区别在于:
1、$.getJSON()的最后一个参数不用写,而$.get()方法的最后一个参数必须是'jsonp'。
2、$.getJSON()虽然省掉了最后一个参数,但这时候,你需要在路径中带上callback=?
或者abc=?
这样的字眼,这样jQuery会自动判断,既然你带上了参数,而且参数值是问号,那么jQuery就认为你想搞jsonp勾当,如果你不加任何参数,或者参数值不是问号,那么jQuery就认为你不想搞jsonp勾当,那么这时候$.getJSON()方法就全等于$.get(...,..., 'json')方法。
同样的,你如果用callback=?
,那么你php里应该是echo $_GET['callback'].'({"a": "张学友"})';
,如果你用abc=?
,那么你php里得是echo $_GET['abc'].'({"a": "张学友"})';
。
$.getJSON('http://外域/xxx.php?abc=?', {各种数据}, function(data) {
console.log(data);
});
结论
要让我选最好用的一个,我选$.get()方法,因为$.get()方法的最后一个参数'jsonp'
能显式声明这个请求是jsonp请求,再一个,$.getJSON()方法的url要加上callback=?
这种字眼,显得繁琐。
$.ajax()方法不到必要时不要用,必须用的时候当然一定要用。
网友评论