对JSONP的学习

2019-06-14  本文已影响0人  青城墨阕

特别想说祸从口出,谨言慎行还是老祖宗的智慧啊,本来能过一个不用加班的周五晚上,就因为一句话得加班做一个有关JSOP的demo,内心的悲伤就像上线前的bug,一泻千里。。。

跨域
  1. 同源策略
    协议、域名、端口号 三者完全一致视为同域,否则为跨域。

2.浏览器为什么不支持跨域
cookie LocalStorage ... 不支持跨域
DOM元素也有同源策略(iframe)
ajax 也不支持跨域

jsonp
  1. 对于jsonp的封装
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>JSONP DEMO</title>
</head>
<body>
<div id="response"></div>
<script>
    function jsonp({url, params, cb}) {
        return new Promise((resolve, reject) => {
            let script = document.createElement('script');
            window[cb] = function (data) {
                resolve(data);
                document.body.removeChild(script);
            }
            params = {...params, cb};
            let arrs = [];
            for(let key in params){
                arrs.push(`${key}=${params[key]}`);
            }
            script.src = `${url}?${arrs.join('&')}`;
            document.body.appendChild(script);
        })
    }
    jsonp({
        url: 'http://localhost:3000/say',
        params: {wd: 'hello jsonp !!!'},
        cb: 'show'
    }).then(data => {
        document.getElementById('response').innerHTML = data;
        console.log(data)
    })
</script>
</body>
</html>

2.对于服务端的封装(利用node)
2.1 npm install express
2.2 server.js服务端的代码

//server.js 服务端
let express = require('express');
let app = express();
app.get('/say', (req, res) => {
    let {wd, cb} = req.query;
    console.log(wd);
    res.end(`${cb}('HELLO JSONP !!! ')`)
})
app.listen(3000);

2.3 启动服务,在浏览器打开http://localhost:3000/
3.运行

前端结果.jpg
服务端结果.jpg
总结

jsonp就是利用< script >标签不会产生跨域的问题来发送跨域请求的;
优点:简单、方便
缺点:1.只能发送get请求; 2.不够安全。

实现方法二
export const getJsonp = (options, getJsonpCallback) => {

    let callbackID = `jsonp_${Date.now()}_${Math.ceil(Math.random() * 100000)}`; // 随机生成callbackID

    let container = document.getElementsByTagName('head')[0];

    let scriptNode = document.createElement('script');

    let data = options.data || {};

    let url = options.url;

    let params = [];

    data.callback = callbackID; // 加上callback参数,服务端接口数据根据callback返回函数

    for (let key in data) { // 遍历参数,把参数组成数组[name=zhangsan,age:18]

        params.push(key + '=' + data[key]);

    }

    url += (/\?/.test(url)) ? '&' : '?'; // 判断原url是否已经有‘?’,如有给url拼接‘&’,则拼接‘?’

    url += params.join('&');

    // url拼接参数最终变成www.baidu.com/?name=zhangsan&age=18&callback=jsonp_1526006949894_87849

    scriptNode.id = callbackID; // 设置script节点id以便后面删除

    scriptNode.src = url;

    window[callbackID] = function (response) {

        // 定义全局函数,注意函数名是callbackID是跟上面定义的参数data["callback"]=callbackID是一致的

        // 服务端接口是根据客户端传的callback而返回callbackID({"code":0,"error":"操作成功","data":{}})

        getJsonpCallback(response);

        // 当客服端请求接口时即调用了函数callbackID({"code":0,"error":"操作成功","data":{}}),刚好是这里我们定义

        // 的全局函数,于是就拿到了数据response

        let script = document.getElementById(callbackID);

        container.removeChild(script); // 通过script节点id删除script节点

    };

    scriptNode.type = 'text/javascript';

    container.appendChild(scriptNode);
};
上一篇 下一篇

猜你喜欢

热点阅读