[聚合文章] 秒建一个 json 转 jsonp 的中间层服务器

JSONP 2016-12-22 13 阅读

问题来源

期末的一个作业,我和同学打算建一个前后端分离的 Web 项目。他用 java 写了一个 api server,而我则构建前端。

我们的 api 抄了别人的一套设计,但只有自己实现的接口遇到了跨域资源请求被禁止的问题。

经过一番调查,我发现别人的接口获取的数据其实是 jsonp 格式,只是文档里让你看起来像获取 json 一样。

jsonp 和 json

我翻开 《JSON 必知必会》 发现发现其 6.3.2 小节有介绍 jsonp

json 我就不多讲了,我们看看 jsonp 是怎么一回事。

我们用 jQuery 向服务发起一个 ajax 请求 jsonp 数据(注意 dataType 字段):

$.ajax({
  method: 'GET',
  url:"http://localhost:3000/login",
  dataType:"jsonp",
  data: {
    userid: that.userid
  },
  success(data, status, xhr) {
    console.log(data);
  }
})

浏览器实际向服务器发起的请求 url 是这样的(注意 callback 这个查询参数):

http://localhost:3000/login?userid=h&callback=jsonp

从服务器返回的参数竟然是一段 javascript 代码:

jsonp({
  "success": false,
  "code": 13
});

原来, jsonp 是这么工作的:它通过动态地向页面插入 <script> 的方式获取数据。

我们使用的 jQuery 库的函数做好了很多工作,让它感觉和获取 json 一样。(js原生写法可以看《JSON 必知必会》6.3.2)

既然知道是怎么一会事了,我该如何补救呢?

解决办法

1. 改 java 服务器端代码

这个方法很现实,不过:

  • 老实说我 java 已经不会写了,其对于我来说是 Readonly。
  • 找同学修改,不太好意思呢。

2. 做个转换的中间层

对于我个准前端来说,还是 node.js 最友好。

实现思路大致如下:

-> 获得请求
-> 所有请求转发 java 服务器
-> 从 java 服务器获得的 json 并包装成 callback(json),也就是jsonp
-> 回复

像这个样子:

---------------     请求JSONP      ---------------      请求JSON       --------------- 
|             |------------------>|    json      |------------------>|              |
|    浏览器    |                   |     to       |                   |     服务器    |
|             |<------------------|    jsonp     |<------------------|              |
---------------     答复JSONP      ---------------      答复JSON       ---------------

原来我的想法是通过 node 的原生 api 来做,后来想起原来一直拿来做静态 api server 的 json-server 模块,结果寥寥几行代码就搞定了:

var server = require('json-server')();
var request = require('request');

var serverUrl = 'http://the.url.of.json.server';

server.get('*', function (req, res) {
  request(serverUrl + req.url, function (error, response, body) {
     res.jsonp(JSON.parse(response.body));
  });
});

server.listen(3000);

(同学 api 实现得不太好,错误的参数会返回 tomcat 的 html 页面,所以我是做了错误处理以防崩溃,上面代码简便起见不处理了)

json-server 还有提供网页资源的功能,如果页面是这里提供,那么直接转发 json 也是可以的,不跨域了嘛。

总结

最后再啰嗦点其他东西:

  1. 我觉得别人的 API 是这样设计的:当请求参数有 callback 时答复 jsonp ,没有则是 json ,这样服务器可以多端通用啦!这个参数取名叫 callback 难道是业界通用?
  2. 其实跨域也不是只有 jsonp 一种办法,还有更安全的 跨域资源共享(cross-origin resource sharing,CORS) 技术,也在《JSON 必知必会》6.3 里。
  3. 我为什么要写这篇文章呢?这里其实没什么技术含量,只是我网上一搜全是 Java、PHP 服务器上的方法,那就不是很容易看明白。难道遇到这问题最多的不是前端程序员吗?

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。