天天看點

JavaScript學習 -- jsonp跨域請求

作者:之乎者也吧呀

在現代 Web 應用程式的開發中,由于跨域通路的限制,經常需要在不同的域之間傳輸 JSON 資料。但是,浏覽器強制遵循同源政策,限制了浏覽器從一個域向另一個域請求資料的能力。為此,我們可以使用 JSONP(JSON with Padding)技術,它通過動态建立 script 标簽實作了跨域傳輸 JSON 資料。

JSONP 實作了一個簡單但非正式的協定,在用戶端發出一個 GET 請求時,服務端傳回一些 JavaScript 代碼,使用戶端能夠利用這些代碼執行回調。JSONP 非常适合用于建構跨域的 JSON 資料請求,但不能用于 POST 請求等其他類型的 Ajax 請求。本文将介紹如何在JavaScript中使用JSONP,并提供一個實際的例子。

實作JSONP

JSONP 可以通過以下代碼實作:

function jsonp(url, callbackName, callback) {
  const script = document.createElement('script');
  script.src = `${url}?callback=${callbackName}`;

  window[callbackName] = (data) => {
    callback(data);
    document.body.removeChild(script);
  };

  document.body.appendChild(script);
}
           

我們可以看到,這個函數有三個參數:

  • url: JSONP 資料請求的 URL。
  • callbackName: 在服務端接受回調函數名的參數名。
  • callback: 接收 JSONP 資料的回調函數。

這個函數會動态地建立一個新的 script 标簽,為擷取 JSONP 資料請求 URL 添加一個查詢參數 callback=callbackName。回調函數的名字将保留在查詢參數中,以便服務端能夠讀取。

然後,在全局命名空間中,我們暴露這個名為 callbackName 的回調函數,并在腳本标簽的 load 事件處理函數上執行這個函數。核心代碼如下:

window[callbackName] = (data) => {
    callback(data);
    document.body.removeChild(script);
};
           

最後,我們再将新建立的 script 标簽添加到文檔中。因為該代碼是通過 <script> 标簽上定義的回調函數來執行的,是以這個 JSONP 請求的響應将被直接注入到我們的 JavaScript 中。

完整的代碼如下:

function jsonp(url, callbackName, callback) {
  const script = document.createElement('script');
  script.src = `${url}?callback=${callbackName}`;

  window[callbackName] = (data) => {
    callback(data);
    document.body.removeChild(script);
  };

  document.body.appendChild(script);
}

jsonp('https://api.github.com/users/octocat', 'myCallback', (data) => {
  console.log(data);
});
           

在這個例子中,我們向 GitHub API 發送了一個 JSONP 請求,當響應傳回時,在控制台列印響應資料。此外,我們利用服務端接受 callback=myCallback 參數,來建立了用于響應資料的回調函數。

JSONP 的優缺點

JSONP 的優點:

  • 浏覽器支援良好,能在絕大多數環境下正常使用。
  • 不需要 Ajax 請求,無需 XMLHttpRequest 對象,不需要進行跨域 AJAX 的額外工作。

JSONP 的缺點:

  • 安全性問題。由于是在全局作用域上執行代碼,是以惡意攻擊者可以通過 JSONP 某些特定的接口來進行 CSRF(跨站請求僞造)。是以,我們需要在服務端進行一些針對性的安全政策。
  • 隻支援 GET 請求,不能支援 POST 等其他類型的 AJAX 請求。
  • 隻支援文本請求,不能傳輸二進制圖像、JSON、XML 等類型的檔案。

總結

JSONP 是一個使用非常廣泛的跨域請求技術。通過簡單的回調的方式,能友善地實作從不同域名的服務端動态地獲得 JSON 資料。雖然使用起來比較友善,但也存在某些限制。JSONP 展現了一種傳統 JavaScript 方式,如果不需要傳輸敏感資料或處理安全要求比較高的場景,我們仍然可以使用此技術。