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 中则会出现歧义,只有手动编码后才能让服务器端正确解析。


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

查看所有标签

猜你喜欢:

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

移动风暴

移动风暴

[美]弗雷德·沃格尔斯坦 / 朱邦芊 / 中信出版社 / 2014-1-1 / 39

也许,除了伟大的乔布斯,每一位奋力改变世界的硅谷英雄,都值得我们肃然起敬。苹果与谷歌十年博弈,关于这场移动平台战争的报道早已铺天盖地,而这是第一次,我们能听到幕后工程师的真实声音。两大科技巨人用智能手机和平板电脑颠覆了电脑产业。它们位处变革的中心,凭借各自的经营哲学、魅力领袖和商业敏感度,把竞争变成了残酷对决。商业记者沃格尔斯坦报道这场对抗已逾十载,在《移动风暴》中,他带领我们来到一间间办公室和会......一起来看看 《移动风暴》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具