基于Promise实现jsonp

jsonp原理

简单来说,由于浏览器对安全的限制,默认禁止跨域请求,但是对资源(例如图片、js、css)是允许跨域的,所以基于该特性,jsonp即通过动态生成"script"标签来访问跨域接口,同时提供给服务端一个方法名,服务端返回一个调用该方法名的调用方法,参数即为客户端想要的数据。
简单实现
// 引入qs模块序列化请求参数
import qs from 'qs'

/**
 * 获取随机的jsonp回调方法名
 * @returns {string}
 */
const getRandomFunctionName = () => {
  // 固定前缀 + 随机数转成36进制字符串
  return '__JSONP__' + Math.random().toString(36).substring(2)
}

/**
 * jsonp请求
 * @param url 请求地址,推荐使用"//"不加协议类型开始
 * @param data 请求参数
 * @param ops 附加属性
 * @returns {Promise<any>}
 */
export const jsonp = (url = '', data = {}, ops = {}) => {
  return new Promise((resolve, reject) => {
    // 创建script标签
    const script = document.createElement('script')
    script.type = 'text/javascript'

    // 格式化url,去除末尾多余的 "?" "&"
    let src = url.replace(/[&|?]+$/, '')

    // jsonp 全局回调函数名
    let callback = getRandomFunctionName()
    while (window[callback]) {
      callback = getRandomFunctionName()
    }

    // 设置超时
    const timeoutId = setTimeout(() => {
      window[callback] = () => {
        // 删除全局回调函数
        try {
          delete window[callback]
        } catch (e) {
          window[callback] = undefined
        }
      }
      // 移除script标签
      document.body.removeChild(script)
      reject(new Error(`JSONP timeout`))
    }, (ops.timeout || 30) * 1000)

    // jsonp 全局回调函数
    window[callback] = (data = {}) => {
      // 清除超时
      clearTimeout(timeoutId)
      // 删除全局回调函数
      try {
        delete window[callback]
      } catch (e) {
        window[callback] = undefined
      }
      // 移除script标签
      document.body.removeChild(script)
      resolve(data)
    }

    // 拼装请求参数,默认服务端接受方法名的属性为"callback",可以在ops里指定
    Object.assign(data, {[ops.callback || 'callback']: callback})

    // qs 序列化参数、并追加参数
    script.src = `${src}${src.indexOf('?') > 0 ? '&' : '?'}${qs.stringify(data, {arrayFormat: ops.arrayFormat || 'repeat'})}`
    // jsonp 异常
    script.onerror = e => {
      // 清除超时
      clearTimeout(timeoutId)
      const target = e.target || e.srcElement
      // 移除script标签
      document.body.removeChild(script)
      reject(new Error(`JSONP Error: fail to load ${target.src}`))
    }
    // 挂载script标签
    document.body.appendChild(script)
  })
}

// jsonp调用
jsonp('//www.xxx.xxx/api/getXxx', {name: 'luyantao', age: '30'}).then((result = {}) => {
  console.log(result)
})
复制代码

转载于:https://juejin.im/post/5c481f41f265da612415c1f4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值