跨域请求之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范畴。

那么怎么实现动态请求数据和设置回调函数处理数据呢?

  1. 动态生成script标签
  2. 将url赋值给src
  3. 注册回调函数
  4. 将script标签append进dom树
  5. 执行回调函数

 

 

 

代码如下:

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

https://www.cnblogs.com/ricesm/p/5055043.html

posted @ 2020-04-15 18:09  想学JS的前端  阅读(199)  评论(0编辑  收藏  举报