jsonp详解

259 阅读2分钟

这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战

前言

今天我们来讲一讲跨域的问题,我们常见的跨域方法有jsonp,cors,还有使用一些中间件进行跨域,这篇文章主要讲jsonp跨域的方法,以及jsonP封装,让我们一起来看看吧。

JSONP

jsonp就是利用web页面调用js文件(一般拥有src属性的标签可以跨域的特点,例如script,img,iframe等)进行跨域,服务器端动态生成数据,一般为json格式的文件。客户端利用如script标签对JSON文件调用成功之后,也就获得了自己所需的数据,然后就按照自己需求进行处理和展现了。

JSONP封装

下面我们对json进行封装:

1.jsonp概念与封装注意点:

代价:需要前后端联动 精髓:自动的由插件生成方法名,并在当前的页面动态的生成函数 然后再生成的函数里头调用用户预留的回调函数 插件:自动化的去模拟基于script去实现跨域请求的过程(对用户来说是黑盒子) 参数拼接:url已经是带参的。和不带参的 id优化 额可以添加一个容器来管理id

2.自己封装的jsonp
2.1)js代码(加注释讲解)
<script>
    /**
     * 1.声明一个jsonP插件对象
     * 作用:隔开作用域
     */
    let jsonP = {};
​
    /**
     *2.在插件对象中创建两个名字备用符数组
     */
    jsonP.char = {
        Number: '0123456789',
        Letter: 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
    }
    /**
     * 通过随机数抽取备用字符数组库拼凑函数id
     * @param charLen
     * @param numLen
     */
    jsonP.newFunId = function (charLen, numLen) {
        let id = '';
        for (let i = 0; i < charLen; i++) {
            id += this.char.Letter.charAt(Math.random() * 52)
        }
        for (let j = 0; j < numLen; j++) {
            id += Math.floor(Math.random() * 10);
        }
        return id;
    }
    /**
     * 拼接路径
     * @param url
     * @param key
     * @param value
     */
    jsonP.jointUrl = function (url, key, value) {
        if (url && key && value) {
            let sign = "&"
            //如果是第一次
            if (url.indexOf('?') == -1) {
                sign = '?'
            }
​
            url += sign + key + "=" + value
        }
        return url;
    }
    /**
     封装err属性方便
     */
    jsonP.err = function (msg) {
        console.error(msg)
    }
​
    /**
     * 发送请求函数
     * @param options
     */
    jsonP.req = function (options) {
        let jsonId={};
        //1.生成方法名
        jsonId.funId = this.newFunId(4,8);
        let Userurl = options.url;
        let Userdata = options.data;
        if (!options) {
            this.err("输入不能空")
            return;
        } else if (!Userurl) {
            this.err("url不能空")
            return;
        } else if (!Userdata) {
            //如果没有data,初始化
            Userdata = {};
        }
        //将函数名赋值给userdata的回调函数属性中
        Userdata.callback = jsonId.funId;
        for (let key in Userdata) {
            Userurl = this.jointUrl(Userurl, key, Userdata[key])
        }
        let script = document.createElement('script');
        script.setAttribute("id" , jsonId.funId);
        script.setAttribute("src" , Userurl);
        //动态生成函数
        let callback=function (result) {
            console.log("xxxxxxx")
            //业务逻辑回调
            if (options.callback){
                try {
                    options.callback(result)
                }catch (e) {
                    this.err(e.message)
                }
            }
            //善后
            let tmp=document.getElementById(jsonId.funId)
            tmp.parentNode.removeChild(tmp);
            eval(jsonId.funId+'=null')
        }
        eval("window."+jsonId.funId+"=function(result){ callback(result) }")
        document.head.appendChild(script)
​
    }
        //测试调用函数
    let test=function () {
        jsonP.req({
            url:"http://localhost:3000/jsonpx",
            data:{
                a:"111"
            },
            callback:function (result) {
                alert("成功"+result)
            }
        })
    }
</script>
2.2)服务端测试代码
router.get('/jsonpx', async function (req, resp, next) {
    let callback=req.query.callback;
    let data=req.query.a;
    if (!data){
        resp.send(`${callback}('洪吉林:我是服务端代码')`)
    }
    resp.send(`${callback}('洪吉林:我是服务端代码`+data+`')`)
})

总结:这就是使用jsonp进行跨域的方法,封装方面可能还可以做的更简便一些,这就需要各位掘友的思维了,我就讲到这里,下一章我们讲cors进行跨域吧。