JSONP 实现

栏目: Json · 发布时间: 6年前

内容简介:JSONP 实现

JSONP 是解决跨域问题的一种方案,不同于 JSON,其并不是一种数据交换格式,而只是一种绕过跨域的技巧。

JSONP

JSONP 的原理非常简单,为了克服跨域问题,利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 js。一般来说我们约定通过一个参数来告诉服务器 JSONP 返回时应该调用的回调函数名,然后拼接出对应的 js。已微博 API 为例,这个参数名是 _cb

我们可以写一个简单的版本:

function JSONP({
  url,
  params,
  callbackKey,
  callback
}) {
  // 在参数里制定 callback 的名字
  params = params || {}
  params[callbackKey] = 'jsonpCallback'
    // 预留 callback
  window.jsonpCallback = callback
    // 拼接参数字符串
  const paramKeys = Object.keys(params)
  const paramString = paramKeys
    .map(key=> `${key}=${params[key]}`)
    .join('&')
    // 插入 DOM 元素
  const script = document.createElement('script')
  script.setAttribute('src', `${url}?${paramString}`)
  document.body.appendChild(script)
}

JSONP({
  url: 'http://s.weibo.com/ajax/jsonp/suggestion',
  params: {
    key: 'test',
  },
  callbackKey: '_cb',
  callback(result) {
    console.log(result.data)
  }
})

会在命令行看到 ["TEST", "特殊泰帮承"] ,注意这里新浪微博的 API 只支持 HTTP,所以我们只能在 HTTP 页面上测试。

JSONP 实现

同时进行多个请求

上面的流程有一个问题,就是在只有一个 JSONP 调用时它工作的很正常,但是当出现两个或者以上的请求,回调函数就会被覆盖,这样会出现混乱。为了解决这个问题,我们需要对所有的回调函数进行编码,并且在调用时告诉后端对应的独一无二的编号。

除此之外,污染全局空间显然是个不明智的选择,这个问题解决起来倒是非常简单,扔到 JSONP.xxx 下即可。

function JSONP({
  url,
  params,
  callbackKey,
  callback
}) {
  // 唯一 id,不存在则初始化
  JSONP.callbackId = JSONP.callbackId || 1
  params = params || {}
    // 传递的 callback 名,和下面预留的一致
  params[callbackKey] = `JSONP.callbacks[${JSONP.callbackId}]`
    // 不要污染 window
  JSONP.callbacks = JSONP.callbacks || []
    // 按照 id 放置 callback
  JSONP.callbacks[JSONP.callbackId] = callback
  const paramKeys = Object.keys(params)
  const paramString = paramKeys
    .map(key=> `${key}=${params[key]}`)
    .join('&')
  const script = document.createElement('script')
  script.setAttribute('src', `${url}?${paramString}`)
  document.body.appendChild(script)
    // id 占用,自增
  JSONP.callbackId++
}

JSONP({
  url: 'http://s.weibo.com/ajax/jsonp/suggestion',
  params: {
    key: 'test',
  },
  callbackKey: '_cb',
  callback(result) {
    console.log(result.data)
  }
})
JSONP({
  url: 'http://s.weibo.com/ajax/jsonp/suggestion',
  params: {
    key: 'excited',
  },
  callbackKey: '_cb',
  callback(result) {
    console.log(result.data)
  }
})

可以看到现在请求的都是 http://s.weibo.com/ajax/jsonp/suggestion?key=test&_cb=JSONP.callbacks[1] 这样的,然后得到的 js 也是 JSONP.callbacks[1]() ,这样就不会有冲突的问题,也不污染全局域。

URI编码

上面的代码仍然存在一个小问题,

JSONP({
  url: 'http://s.weibo.com/ajax/jsonp/suggestion',
  params: {
    a: '545&b=3'
    b: '5',
  },
  callbackKey: '_cb',
  callback(result) {
    console.log(result.data)
  }
})

会导致 a 的内容直接被拼写进字符串,导致覆盖了 b 的值,而用户真的只是想让 a 的值为 trdgd&b=2 而已。解决方案也简单,进行 URI 编码即可, encodeURIComponent('trdgd&b=2') 的结果为 trdgd%26b%3D2 。即将上面参数处理的部分改为

const paramString = paramKeys
  .map(key=> `${key}=${encodeURIComponent(params[key])}`)
  .join('&')

这里值得一提的是,由于最终的 URL 不能包含 ASCII 码以外的字符,所以其实当使用中文或者特殊字符时其实会被自动编码。而 +,空格,/,?,%,#,&,= 等字符在 URL 中则会出现歧义,只有手动编码后才能让服务器端正确解析。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

实战Linux编程精髓

实战Linux编程精髓

罗宾斯 / 中国电力出版社 / 2005-7 / 59.80元

编写应用软件,特别是那些比较重要的软件,毫无疑问要涉及到系统调用。在UNIX/Linux环境下编程更是如此。要想编写优秀的软件,就必须熟悉这些系统调用的方方面面。通过阅读这本书,你能够快速地掌握这些重要技术,以构建严谨的Linux软件。全书主要分为三大部分:第一部分讨论了基本的编程问题,包括Linux编程环境、基本的文件和进程管理与操作、内存操作,还介绍了一些基本的库接口。第二部分比较深入地讨论了......一起来看看 《实战Linux编程精髓》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具