秒建一個 json 轉 jsonp 的中間層伺服器

Cyang發表於2016-12-22

問題來源

期末的一個作業,我和同學打算建一個前後端分離的 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 伺服器上的方法,那就不是很容易看明白。難道遇到這問題最多的不是前端程式設計師嗎?

相關文章