服务与支持 |咨询热线 0931-8733767
  • 金城在线
  • 公司简介
  • 发展历程
  • 企业文化
  • 售后服务
  • 工作机会
  • 联系我们

聊聊 JSONP 的 P

来源:发布时间:2018-3-12 9:27:29

JSONP 是 JSON With Padding 的缩写。一个典型的 JSONP 请求如下

<script src="http://server.example.com/users/abc?callback=parseResponse"></script>

返回值为

parseResponse({"name": "Foo", "id": 1234, "rank": 7});


其中 parseResponse 是由 callback 参数指定的,也就是 JSONP 中的 P(adding)。这个 P 可不简单,第一个想到这么用的人,绝对是个大牛。因为有了这个 P,解决了好些难题:

1. 回调问题。只要发出 script 请求,自动等待 callback 回调就好,并且精准得能秒杀 `onload` 等方案。

2. 跨域问题。因为浏览器的同源策略,跨域一直是前端的难题。跨域与安全息息相关,JSONP 没有破坏安全性,同时却具备了全面跨域能力。巧妙而实用。

3. 协作问题。后端专注与数据处理与输出,前端专注与数据展现。除了 JSON 数据本身的格式约定,其他约定仅仅需要一个 P 就好。

好了,再说下去,估计很多人会不乐意了。JSONP 的劣势也很明显:

1. 无中间状态。不像 XHR(XMLHttpRequest) 那样,有丰富的 status 、readyState 等属性,可以很精准地知道各种状态。

2. 只能 GET。不像 XHR 那样,可以全方位支持 GET、POST、PUT、DELETE。

3. 只能异步。XHR 是可以同步的,估计很多人没用过,同步其实是 XHR 的默认行为(省略 open 的第三个参数就代表同步)。

本文不聊其他的,专注聊聊那个P。

回到开头那个例子:

http://server.example.com/users/abc?callback=parseResponse

parseResponse 是一个全局函数。当页面上很多 JSONP 请求时,就有可能出现很多全局函数。虽然全局变量并不一定是恶魔,但不好好管理的全局变量真的有可能成为恶魔。管理的方案之一是给 P 引入命名空间:

http://server.example.com/users/abc?callback=JSONP.parseResponse

这样,所有 JSONP 的回调处理函数就都有了根,可以避免与其他函数的潜在冲突。

可是,这还得绞尽脑汁给 JSONP.xxx 命名,经常大家会想到一块,比如 xxx 经常会不谋而合:

callback

handle

parseData

_Callback

jsonp


这种不谋而合,虽然代表着英雄所见略同式的欣慰,但更多的是:我靠,你怎么也取这个名字?这可怎么解决呢?来试试 jQuery 类库。jQuery 的优秀绝对不仅仅是给你一个 $ 符号,jQuery 在很多方面考虑得非常周到:

$.getJSON("http://server.example.com/users/abc?callback=?",

function(data) {

  console.log(data.name); // => Foo

});


很神奇的,只需要指定下 callback=? 就好,再也不用为命名犯愁了。原理是 jQuery 帮你随机命名了一个当前页面唯一的全局 callback 函数,并且与 success 调用串接了起来。这样,就可以像使用 XHR 一样直接在回调中拿到 data 数据。jQuery 再好,也抵挡不住 winter 等神人的不喜欢。这时,我们可以用各种 loader 来实现,比如:


seajs.use("http://server.example.com/users/abc?callback=define",

function(data) {

  console.log(data.name); // => Foo

});


通过 RequireJS、SeaJS、OzJS 等 XMD loader,我们也不再需要为回调函数名烦恼,只要给 callback 传入 define 就好。如果你有全站使用 loader 方案,更进一步,可以约定没有传 callback 参数时,默认就是 define. 这意味着对于静态 JSON 数据来说,可以静态化:


seajs.use("http://server.example.com/users/abc.js",

function(data) {

  console.log(data.name); // => Foo

});


这样,服务端的 JSONP 数据直接可以是静态文件:


define({"name": "Foo", "id": 1234, "rank": 7});


这带来的好处看起来很小,实际上很有用。因为这意味着数据可以提前处理好,可以提前缓存,甚至可以静态化存储到 CDN 上,可以缓存到用户浏览器上。静态化的好处,谁用谁知道。用 define 固定住 callback 名,配合浏览器端的 loader,我们可以传输各种数据:

define([ ... ]); // 数组格式,比如搜索提示数据

define("...."); // 直接字符串,比如模板

这个方案,鄙人很无耻,还申请过一个专利,叫 JSONM 协议,M 是 Module(模块)。不过以上用法不在专利保护内容里,大家可以放心大胆用。


P 还可以摇身一变,从 JSONP 变成 XHR,比如

http://server.example.com/users/abc?type=xhr

通过 type 参数,服务端就会直接返回 JSON 数据,这样就可用在 XHR 调用中。Google 的 API 中有类似的设计,很灵活。

JSONP 的这个 P,到此就谈完了。除了这个 P,更有挑战的是 JSON 数据本身的设计。这里面学问大了去,等有时间再细说。


相关文章
  • 预约专家

    为您提供一对一解决方案
    立即预约
  • 售前咨询

    周一至周五9:00——17:30
    立即咨询
  • 联系方式

    13919049954

    全国7×24小时热线服务
  • 免费报价

    专属专业顾问1对1报价
    免费报价