跨域之jsonp

133 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情

jsonp

实现跨域的方式有有很多种,这里我们介绍 jsonp 的方式:

通过 script 标签,返回一个函数,函数名由用户传入。

我们以百度为示例,在百度搜索框输入 a 后,通过控制台拿到它的请求。删除掉无用参数后,请求的 url 为:https://www.baidu.com/sugrec?prod=pc&wd=a&cb=show

将其丢进浏览器,可以看到返回的内容如下:(注意,这里我将 cb 的值改为了 show)

image.png

调用jsonp请求

以上面的请求为例,假设我们的页面需要请求上面的搜索内容

通过该 url 返回的内容可以发现,其实它返回的是一个函数 的执行,并且函数名为我们传参中 cb 的值(show)

那么我们其实就可以将这个请求作为一个 show 函数的调用,只需要在我们自己的代码中编写 show 函数即可。

<body>
  <script>
    // 这里定义函数,会在下面的script请求中执行
    function show(data) {
      // data会由下面的请求传入
      console.log(data)
    }
  </script>
  <!-- 请求回来后,就是一个函数执行 -->
  <scirpt src="https://www.baidu.com/sugrec?prod=pc&wd=a&cb=show""></scirpt>
</body>

上面的代码,等同于:

<body>
  <script>
    function show(data) {
      console.log(data)
    }
    show({q: "a", p: false, g: [{"type":"sug","sa":"s_1","q":"a站"},{"type":"sug","sa":"s_2","q":"a股"} ...]})
  </script>
</body>

这样就是一个完整的 jsonp 调用了。

封装jsonp请求

上面的代码调用是原始的 jsonp 调用,虽然能完成功能,但是并不方便使用,我们需要将其封装的更为易用

  • 使用方式
// 类似 jquery 中的使用方法
jsonp({
  url: "https://www.baidu.com/sugrec",
  params: { prod: "pc", wd: "a" },
  cb: "show"
}).then(data => {
  console.log(data)
})
  • 实现jsonp 函数
function jsonp({ url, params, cb }) {
  // 返回一个 Promise 对象(因为加载url是异步的)
  return new Promise((resolve, reject) => {
    // 通过动态创建script标签的方式,使用jsonp
    let script = document.createElement("script")
    window[cb] = function(data) {
      resolve(data);
      // 用完script后删除
      document.body.removeChild(script)
    }
    // 组装参数
    params = {...params, cb} // wd=b&cb=show
    let arrs = []
    for(let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join("&")}`
    // 一定要放入页面中,才会进行加载
    document.body.appendChild(script)
  })
}

我们可以看到控制台打印出了 data 的内容

image.png

完整代码如下


<body>
  <script>
    function jsonp({ url, params, cb }) {
    return new Promise((resolve, reject) => {
      let script = document.createElement("script")
      window[cb] = function(data) {
        resolve(data);
        // 用完script后删除
        document.body.removeChild(script)
      }
      params = {...params, cb} // wd=b&cb=show
      let arrs = []
      for(let key in params) {
        arrs.push(`${key}=${params[key]}`)
      }
      script.src = `${url}?${arrs.join("&")}`
      
      document.body.appendChild(script)
    })
  }
  jsonp({
    url: "https://www.baidu.com/sugrec",
    params: { prod: "pc", wd: "a" },
    cb: "show"
  }).then(data => {
    console.log(data)
  })
  </script>
</body>