跨域请求之jsonp
聊聊什么是jsonp
说到son大家应该是很熟悉的,jsonp和json只差了一个字母,那么他们是不是他们有着非常密切的关系呢?答案是确定的。jsonp全称”JSON with Padding“,意思应该是”填充的json“。那么问题就来了,填充指的是什么,怎么填充呢?
聊聊script标签
<script> 标签用于定义客户端脚本,比如 JavaScript。<script type="text/javascript">
script 元素既可以包含脚本语句,也可以通过 src 属性指向外部脚本文件。
当使用src属性时,script标签就会去请求目标资源。利用这一特性,我们就可以用script标签去请求服务器的json数据,这就是jsonp。
其实真正可以使用src属性的标签并不只有script,img等标签一样可以,但他们都不用于请求json,因此不属于jsonp范畴。
那么怎么实现动态请求数据和设置回调函数处理数据呢?
- 动态生成script标签
- 将url赋值给src
- 注册回调函数
- 将script标签append进dom树
- 执行回调函数
代码如下:
function jsonp( url, fn ){
//构造一个函数到window上
var fnName="__jsonpFn"+Math.random().toString().replace(".","");
//创建script标签
var script=document.createElement("script"),
//获得页面中的head标签
head=document.head;
//设置script标签请求的src,记得带有参数
script.src=url + "?callback=" + fnName;
//先绑定函数,再请求更加安全
window[fnName]=function( data ){ //发回数据调用的内容
fn(data); //用户写的函数
//删除函数,删除内容
delete window[fnName];
head.removeChild( script );
};
//将script标签加到页面中,浏览器就会自动的请求下载js格式的字符串
head.appendChild(script);
}
服务端:
var express = require("express")
var app = express()
app.get('/api', function (req, res) {
var data={
name: "王八",
age: 100
}
//返回的类型必须设置为javascript
res.type('text/javascript')
//前端路由中的参数获取,req.query。
console.log("query",req.query);
res.send(req.query.callback+'(' +JSON.stringify(data)+')')
//这里的数据必须转化为字符串,否则传入一个对象浏览器无法解析
// res.send(req.query.callback+'(' +data+')')
})
app.listen(3000)
console.log("listen the port 3000");
补充说明:
也许有的小伙伴不明白回调函数是怎么被触发的,关键在这两行代码
res.type('text/javascript')
res.send(req.query.callback+'(' +JSON.stringify(data)+')')
这两行相当于往你注册的script标签写入了fnName(data),作用便是触发前面window上注册的回调函数,而这个data在服务端动态生成并以实参形式嵌入在返回的函数中,其实这就是上面提到的”填充的json“,
真正的json数据就是这样被填充在实参里返回了。
整个过程就相当于你手动干了这么一件事:
<script type="text/javascript" src="url"> data = '{"a":1}'
fnName(data) </script>
服务器的作用就是生成了这个data并嵌套在实参里面返回给你了。
优缺点:
1.优点
1.1它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
1.2它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
1.3在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分 开了。我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个jsonp服务。
2.缺点
2.1它只支持GET请求而不支持POST等其它类型的HTTP请求
2.2它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
2.3 jsonp在调用失败的时候不会返回各种HTTP状态码。
2.4缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。
评价:
JQ等框架当年都有封装好的jsonp请求,但如今的业务中几乎都看不到jsonp请求了,如今用的最多的都是cors,从便捷度和安全考量,cors都好于jsonp。但jsonp的思想仍在使用,比如利用CDN引入图片等,其实本质上和jsonp原理一样,都是利用src属性去请求跨域资源,只是数据的形式不一样而言。
参考了以下文章:
https://cloud.tencent.com/developer/article/1145813
https://blog.csdn.net/weixin_38888773/article/details/81974348