JSONP原理及实现

182 阅读1分钟

每天做个总结吧,坚持就是胜利!

    /**
        @date 2021-05-24
        @description JSONP原理及实现
    */

壹(序)

JSONP(JSON with Padding),是一种解决跨域的方法,兼容性好,但是只能处理GET请求;其原理是利用HTML的script标签没有跨域限制来解决跨域。 需注意一下几点:

  1. 前端的回调函数名,需要与后端匹配,所以最好是前端传入函数名,后端基于此名进行处理;
  2. 后端返回的是一个字符串,前端在数据返回后执行回调;
  3. 回调需要绑定在window上,因为script标签最后的作用域是window;

贰(前端实现)

    const jsonpGet = (url, params, cbName, cb) => {
        const container = document.getElementsByTagName('head')[0];

        const requestEle = document.createElement('script');
        requestEle.src = `${url}?${parmaFormatter(params)}&callback=${cbName}`;
        container.appendChild(requestEle);

        window[cbName] = function (data) {
            cb && cb(data);
            container.removeChild(requestEle);
            delete window[cbName];
        };

        requestEle.onerror = () => {
            window[cbName] = function () {
                cb && cb('has error');
            };
            container.removeChild(requestEle);
            delete window[cbName];
        };
    };

    const parmaFormatter = (params) => {
        const keys = Object.keys(params);

        return keys.reduce((acc, cur, index) => {
          if (index === keys.length - 1) {
              return (acc += `${cur}=${params[cur]}`);
          } else {
              return (acc += `${cur}=${params[cur]}&`);
          }
        }, '');
    };

叁(使用)

    jsonpGet('http://localhost:3000', { a: 1, b: 2 }, 'jsonp_test', (res) => {
        console.log(res);
    });

肆(引申)

实现Promise版本:

const jsonpGet = (url, params, cbName) => {
    const container = document.getElementsByTagName('head')[0];

    const requestEle = document.createElement('script');
    requestEle.src = `${url}?${parmaFormatter(params)}&callback=${cbName}`;
    container.appendChild(requestEle);

    return new Promise((resolve, reject) => {
        window[cbName] = function (data) {
            resolve(data);
            container.removeChild(requestEle);
            delete window[cbName];
        };

        requestEle.onerror = () => {
            window[cbName] = function () {
                reject('has error');
            };
            container.removeChild(requestEle);
            delete window[cbName];
        };
    });
};

jsonpGet('http://localhost:3000', { a: 1, b: 2 }, 'jsonp_test').then(
    (res) => {
        console.log(res);
    }
);