天天看點

JSONP詳解

0、關于JSONP

什麼的JSONP

JSONP(JSON with Padding)是資料格式 JSON 的一種“使用模式”,可以讓網頁從别的網域要資料。另一個解決這個問題的新方法是跨來源資源共享。(參考:https://zh.wikipedia.org/wiki/JSONP)

JSONP的起源

  1. 曾經的Ajax不能跨域請求(現在的也不能,不過有cors)
  2. Web上使用script調用js檔案不存在跨域問題(實際上,隻要擁有src屬性的标簽都允許跨域,比如script,img,iframe)
  3. 那個時候,想要通過web端跨域通路資料,隻可以在伺服器端設法把資料裝進js,然後用戶端調用
  4. 剛好這個時候JSON大行其道
  5. 是以,解決方案就出來,web端像調用腳本一樣來跨域請求伺服器上動态生成的js檔案
  6. 為了便于用戶端使用資料,逐漸形成了一種非正式傳輸協定,人們把它稱作JSONP。

JSONP用來做什麼

通過JSONP的起源,我們大概也知道了JSONP就是為了跨域資源通路的。

1、JSONP實作原理

我們知道,在script标簽中請求的js代碼,到用戶端之後,是能被自動執行的。

我們先構造一個後端(采用node實作):

var http = require('http');

var server = http.createServer((req, res) => {
  var sendObj = {
    url: req.url,
    name: 'test'
  };
  res.write(`callback(${JSON.stringify(sendObj)})`);
  res.end();
});

server.listen(9999, () => {
  console.log('started.')
});
           

我們要使用這個這個資料呢?可以用Ajax,可能會産生跨域問題

另外,可以用如下寫法:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JSONP TEST</title>
</head>
<body>
  <script>
  function callback(obj){
    console.log(obj);
  }
  </script>
  <script src="http://localhost:9999/abc"></script>
</body>
</html>
           

打開這個頁面後,我們會看到控制台會輸出一個對象

Object {url: "/abc", name: "test"}

, 也就是後端傳回的對象。

當使用script請求位址時,會将傳回的字元串,預設當成js解析。由于後端傳回是的callback(xxx),是以會調用本地的callback函數。

從原理上來看,要使用JSONP,必須要後端傳回相應的資料,這個就是JSONP的模式了,允許用戶端傳遞一個callback函數,後端将資料包裹在callback函數中傳回。

從原理也能看出,JSONP并不要求必須傳遞JSON格式的資料,隻要是JS函數能夠認可的資料都是可以傳遞的

2、封裝JSONP調用JSONP

知道了原理,我們很容易能夠實作一個jsonp的函數調用,代碼如下:

window.JSONP = function(url, callback){
  callback = callback || 'callback';
  var result;
  return new Promise((resolve, reject) => {
    var overwritten;
    var scriptEl = document.createElement('script');
    scriptEl.src = url + '?callback=' + callback;
    //加載完成後,删除callback
    scriptEl.onload = function(){
      if(overwritten === undefined){
        delete window[callback];  
      }else{
        window[callback] = overwritten;
      }
      resolve(result);
    }
    //挂載一個callback到window上
    overwritten = window[callback]; //先儲存一個,用完之後再還原
    window[callback] = function(data){
      result = data
    }
    document.head.appendChild(scriptEl);
  });
};
           

如何用?

window.JSONP('http://localhost:9999/abc').then((data) => {
  console.log(data);
});
           

3、擴充

在jQuery中,我們使用jsonp感覺就和使用ajax沒有差別,但實際上它們的底層實作實作是完全不一樣的,畢竟原理都不同。

雖然很多庫和架構都把jsonp封裝到了ajax中,但是一定要記得jsonp不是ajax的一個特例。

目前,除了用jsonp跨域之外,還可以采用服務端代理(通過不跨域的後端程式,發送webClient去請求資料,然後轉發),CORS(API伺服器允許跨域的一種設定)。

繼續閱讀