为什么要知道jsonp,jsonp的作用是什么:
- Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)获取资料,即跨域读取数据。
- 原则上浏览器是不允许请求不同域名的数据的,但是跨域取数据是经常要用的,jsonp就可以解决这个问题。
- 为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略。
同源策略介绍:
- 同源策略:同域名 同端口号 同协议;
- 浏览器有一个“同源策略”的规则: 只有在同域名同端口号和同协议下才能进行数据的请求和传输;
- 不符合同源策略的,浏览器为了安全,会阻止请求;
针对同源策略的解决办法:
- 为了能够访问到不同域名的数据,有两种解决办法:
- 第一就是:cors,由后端设置:Access-Control-Allow-Origin:*
- 这也就是为什么有一些数据可以跨域访问,因为它们后端设置了允许指定接口或者允许所有接口去访问;
- 这个设置可以在Response Headers里看到;
CORS是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制;
- 第二就是:jsonp,由前后端协作去设置;
jsonp的设置:
- 第一种解决办法cors因为是后端设置的,我们无法控制,那我们就可以去控制jsonp来实现跨域问题;
jsonp的原理:(面试重点)
- 动态创建script标签,src属性指向没有跨域限制;指向一个接口,接口返回的格式一定是***()函数表达式
代码解释:
- 访问的接口数据是:
- 代码:
<body>
<button id="mybtn">jsonp</button>
<script>
//调用这个数据里面的函数,拿回来请求的数据
function callbackFunction(obj) {
console.log(obj)
}
mybtn.onclick = function () {
var oscript = document.createElement("script")//动态创建script节点
oscript.src = `https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction`//请求数据的地址
document.body.appendChild(oscript)//将节点插入到body里面
}
</script>
</body>
- 结果:
设置jsonp要满足的条件是:就是满足原理的几点
- 动态创建script标签;
- 指向一个接口,这个接口里的数据必须是“函数名([ ])”这样格式的;
- 所以这就需要后端配合,后端接口形式必须是“函数名([ ])”的;
- 而且要在代码中调用这个函数,也就是这段代码的含义:
- 这个函数名要和网址中的函数名保持一致,不一致拿不到数据;
- 这时候我们可以前端设置这个接口名字,也就是这个函数名,因为我们刚开始调用这个函数的时候,不知道这个函数名是什么,这时候我们就可以使用我们自己定义的函数名,然后更改网址中的路径;
把这个函数名改成我们自己定义的,访问这个地址:
结果:
然后结果也能拿到我们要的数据:
jsonp设置的缺点:
两个缺点:
- onload删除script标签;
- 只能get请求,不能post、put、patch、delete请求;
- 删除script标签:
- 我们在设置jsonp时,会出现的一个问题是:我们每请求一次数据它就动态创建了一个script节点把它插入到body里面,我们其实代码中创建完script,第二步设置src,在第三步将script标签插入到body里,就拿到数据了,但是我们没必要留着这个script标签,所以就要在插入标签,拿到数据以后,就把这个标签给删了。
- 所以我们需要有一个删除script节点的事情要做:
- 插入了很多script标签:
删除代码:
oscript.onload = function(){
//删除当前节点
oscript.remove()
}
完整代码:
<body>
<button id="mybtn">jsonp</button>
<script>
//调用这个数据里面的函数,拿回来请求的数据
function test(obj) {
console.log(obj)
}
mybtn.onclick = function () {
var oscript = document.createElement("script")//动态创建script节点
oscript.src = `https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=test`//请求数据的地址
document.body.appendChild(oscript)//将节点插入到body里面
oscript.onload = function(){
//删除当前节点
oscript.remove()
}
}
</script>
</body>
- 就是先把这个script标签插入到body中,然后再把它删掉,这样我们已经拿到数据了, 标签留着也没用了;
这里纠正一个错误的认识:
- 有些人可能觉得既然要把插入的script删掉,那就当初不要插入标签,因为第二步设置完了src路径以后,不就拿到数据了。
- 不是的
- 这里是第一步创建script标签,第二步设置src路径,第三步是将script标签插入到body里;
- 只有当最后一步将script标签插入到body里才能拿到数据,并不是第二步就拿到数据了;
- 所以我们需要先把script标签插入到body里,然后拿到数据以后,再删除script标签。