fetch-jsonp源码阅读

fetchJsonp源码

源码地址:https://github.com/camsong/fetch-jsonp

jsonp优势

  • 请求数据没有跨域的限制,后台不用考虑跨域问题

  • 对于老版本浏览器更加支持

jsonp缺陷

  • 只支持get请求,不支持其他所有方式的请求(请求方式受到了限制)
  • 只支持get请求,不支持post(不安全因素一)
  • 因为没有跨域,所以调用接口方不能限制ip,安全方面不是很到位(不安全因素二)

使用例子

import fetchJsonp from 'fetch-jsonp';

fetchJsonp(`${document.location.protocol}//xxx.com/v1/pages/list`).then(
  (res) => {
    return res.json();
  },
);

fetchJsonp函数

主要是利用script标签的src属性来请求api,实现跨域。

function fetchJsonp(_url, options = {}) {
  // to avoid param reassign
  let url = _url;
  const timeout = options.timeout || defaultOptions.timeout;

  // defaultOptions.jsonpCallback,默认是'callback'
  const jsonpCallback = options.jsonpCallback || defaultOptions.jsonpCallback;

  let timeoutId;

  return new Promise((resolve, reject) => {
    // 回调函数名称,字符串类型
    const callbackFunction =
      // generateCallbackFunction返回一个随机定义的字符串
      options.jsonpCallbackFunction || generateCallbackFunction();
       
    //用于script标签的id
    const scriptId = `${jsonpCallback}_${callbackFunction}`;

    // 将属性callbackFunction定义在window全局对象上,简单概括就是在window全局对象上定义一个函数

    window[callbackFunction] = (response) => {
      // 返回信息
      resolve({
        ok: true,
        // keep consistent with fetch API
        json: () => Promise.resolve(response),
      });

      // 清除定时器
      if (timeoutId) clearTimeout(timeoutId);

      removeScript(scriptId);

      clearFunction(callbackFunction);
    };

    // Check if the user set their own params, and if not add a ? to start a list of params
    url += url.indexOf('?') === -1 ? '?' : '&';

    // 创建一个script标签
    const jsonpScript = document.createElement('script');

    // 设置src属性
    jsonpScript.setAttribute(
      'src',
      `${url}${jsonpCallback}=${callbackFunction}`,
    );

    // 编码
    if (options.charset) {
      jsonpScript.setAttribute('charset', options.charset);
    }
    // nonce 全局属性是定义了密码学 nonce(“只使用一次的数字”)的内容属性,内容安全策略可以使用它来确定是否允许对给定元素进行获取。
    if (options.nonce) {
      jsonpScript.setAttribute('nonce', options.nonce);
    }

    //
    if (options.referrerPolicy) {
      jsonpScript.setAttribute('referrerPolicy', options.referrerPolicy);
    }
    // 设置跨域
    if (options.crossorigin) {
      jsonpScript.setAttribute('crossorigin', 'true');
    }

    jsonpScript.id = scriptId;

    // 返回一个包括所有给定标签名称的元素的 HTML 集合HTMLCollection
    // 在head标签之后添加script标签
    document.getElementsByTagName('head')[0].appendChild(jsonpScript);

    // 定时器
    timeoutId = setTimeout(() => {
      reject(new Error(`JSONP request to ${_url} timed out`));

      // callbackFunction,移除window上的自定义的callbackFunction
      clearFunction(callbackFunction);
      // 移除script标签
      removeScript(scriptId);

      //
      window[callbackFunction] = () => {
        clearFunction(callbackFunction);
      };
    }, timeout);

    // Caught if got 404/500
    jsonpScript.onerror = () => {
      // 抛出错误
      reject(new Error(`JSONP request to ${_url} failed`));

      clearFunction(callbackFunction);
      removeScript(scriptId);
      if (timeoutId) clearTimeout(timeoutId);
    };
  });
}

export default fetchJsonp;

defaultOptions变量

const defaultOptions = {
  timeout: 5000,
  jsonpCallback: 'callback',
  jsonpCallbackFunction: null,
};

generateCallbackFunction函数

返回一个自定义的随机字符串

function generateCallbackFunction() {
  return `jsonp_${Date.now()}_${Math.ceil(Math.random() * 100000)}`;
}

removeScript函数

移除script标签

function removeScript(scriptId) {
  // 找到script标签
  const script = document.getElementById(scriptId);
  // 移除script标签
  if (script) {
    document.getElementsByTagName('head')[0].removeChild(script);
  }
}

clearFunction

移除全局对象window上的自定义方法或属性

function clearFunction(functionName) {
  // 移除window上自定义属性or方法
  try {
    delete window[functionName];
  } catch (e) {
    window[functionName] = undefined;
  }
}

打包

利用Babel库打包

{
  "scripts": {
    "prepublish": "npm run lint && npm run clean && npm run build",
    "build": "babel src/ --modules umd --out-dir build",
    "clean": "rm -rf build",
    "lint": "eslint src/"
  }
}

babel

Babel是一个帮助你用最新版本的JavaScript编写代码的工具。当您的支持环境不支持某些特性时,Babel将帮助您将这些特性编译为支持的版本。

// ES2020 nullish coalescing
function greet(input) {
  return input ?? "Hello world";
}
function greet(input) {
  return input != null ? input : "Hello world";
}
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值