欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jsonp原理理解

程序员文章站 2024-01-20 21:02:04
...

当我们用ajax请求一个跨域的域名时会报如下错误
Jsonp原理理解
这是因为浏览器基于同源策略,在同源策略下浏览器不允许AjAX跨域获取服务器数据
同源策略是浏览器的安全策略,指的是请求URL地址中的协议,域名和端口都与当前发送请求的页面相同,只要一处不同就是跨域请求。
那如果我们想跨域获取数据是不是就没办法了?我们知道标签的src属性实际上是支持跨域请求的 比如你的img标签可以引用一个网络图片,我们可以通过cdn在script标签上引入一些外部的库

<img src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1584248645076&di=9459c8b9c7d80d56fdc0a24bb61dc208&imgtype=0&src=http%3A%2F%2Fseo-1255598498.file.myqcloud.com%2Ffull%2F65b0ccb0709d96d954318c75a84aff68208696c1.jpg'>
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/jquery.min.js">
</script>

基于这个特性我们可以模拟一下跨域请求
通过script标签请求一个跨域域名

<script type="text/javascript" src='http://www.jsonp.com'></script>

服务端

<?php
echo 123

查看Network
Jsonp原理理解
可以看到获取到服务端的数据但这种方式虽然能获取到数据,我们并不能使用。
如果服务端返回的是一段js代码

<?php
echo "var data = 123";
//js
<script type="text/javascript" src='http://www.jsonp.com'></script>
console.log(data)//结果返回123

通过这种方式我们就可以获取到跨域请求的数据,但这种方式也有缺点。虽然能打印数据但是url地址都被我们写死,不够灵活因此我们想到可以动态的创建script标签动态设置其src属性

//php
<?php
echo "var data = 123";
//js
var script = document.createElement('script');
script.src='http://www.jsonp.com';
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
console.log(data);//异常

但是这种方式也有缺点,通过这种方式我们发送的请求是异步请求,我们可能获取不到服务端的数据
Jsonp原理理解
由于是异步请求,在还没有获取到data时我们就将其打印,所以出现上面错误
一个完美的解决办法就是通过函数调用,既然服务端可以给我们返回一段js代码,并且在请求服务端后我们可以拿到那段js代码,那我们使服务端返回一个JS函数调用,前端定义这个函数即可
这也就是我们下面要说的jsonp

//服务端
<?php

echo "callback(123)";
//js
function callback(data){
		console.log(data)
}
var script = document.createElement('script');
script.src='http://www.jsonp.com';
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);

我们先前就定义好了服务端返回的回调函数,服务端只是返回一个函数调用,当请求完服务器时就相当于在页面生成如下代码,通过这种方式灵活的获取数据

function callback(data){
		console.log(data)
}//请求完成
callback(123);//返回123

实际上面操作就已经完成了一次jsonp,但是还是不够完美,只能说其像jsonp(后面我们会提到其概念),为什么说他不够完美,不知道你有没有发现我们前端定义的函数必须与后端调用的函数一致才能获取到数据吧!在实际开发中我们也不可能要求第三方的回调函数和我们前端定义的函数保持一致吧,那有没有一种方案,使我们定义的函数不管是什么都能正常获取数据呢?肯定有的,我们可以在请求的时候将这个函数名以参数的形式传递给后端,后端拿到这个参数后直接进行函数调用不就可以了吗,此时函数的名称是由前台决定,话不多说直接上代码

//js
function foo(data){
	console.log(data)
}
var script = document.createElement('script');
script.src='http://www.jsonp.com?callback=foo';//传递回调函数名称
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
//php
<?php
$callback = $_GET['callback'];//接收到前台传递的回调函数名
echo $callback."(123)";//拼接函数
//结果输出
123

通过这种方式我们可以自定义函数名,只要保持与传递给服务器的函数名一致即可,但是我们传递的参数名必须与服务端一致,比如服务端接收的参数是callback那么你可以用callback=funcName的方式传递函数,如果服务端接收的参数是_cb那么你传递参数时必须
_cb=funcName
写到这里已经把jsonp的原理实现了,我们来结合上述代码看下他的概念。

jsonp允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了

看到这里你应该理解了jsonp的执行原理了,如果还是很懵请细品。

下一篇Jquery使用jsonp
下下一篇Vue使用jsonp

相关标签: JQ