一、什麼是JSONP
1.1 同源策略
如果兩個頁面擁有相同的協議,埠(如果指定),和主機,那麼這兩個頁面就屬於同一個源。
同源策略分為:
-
DOM
同源策略:禁止對不同源頁面DOM
進行操作 -
XMLHttpRequest
同源策略:禁止向不同源的地址發起HTTP
請求
由此可見,Ajax
禁止跨域。
1.2 JSONP
的原理
JSONP
是JSON with Padding
的簡稱,一般用來解決Ajax
跨域的問題。它是這樣產生的:
-
頁面上呼叫
js
檔案時不受跨域的影響,而且,凡是擁有src
屬性的標籤都擁有跨域的能力,比如<script>
、<img>
、<iframe>
。 -
可以在遠端伺服器上設法把資料裝進
js
格式的檔案裡,供客戶端呼叫處理,實現跨域。 -
目前最常用的資料交換方式是
JSON
,客戶端通過呼叫遠端伺服器上動態生成的js
格式檔案(一般以JSON
字尾)。 -
客戶端成功呼叫
JSON
檔案後,對其進行處理。 -
為了便於客戶端使用資料,逐漸形成了一種非正式傳輸協議,人們把它稱作
JSONP
,該協議的一個要點就是允許使用者傳遞一個callback
引數給服務端,然後服務端返回資料時會將這個callback
引數作為函式名來包裹住JSON
資料,這樣客戶端就可以隨意定製自己的函式來自動處理返回資料了。
二、JSONP
的客戶端具體實現
2.1 上文已指出,頁面可執行跨域的js
程式碼(符合安全策略的),那麼:
<script type="text/javascript">
var localHandler = function (data) {
alert(`跨域的remote.js檔案可以呼叫本函式,帶來的資料是:` + data.result);
};
</script>
<script type="text/javascript" src = "http://remoteserver.com/remote.js"></script>
remote.js
的程式碼:
localHandler({
"result": "我是遠端js帶來的資料"
});
執行後,成功彈出提示視窗,跨域成功。但問題是,如何讓遠端js
知道它應該呼叫的本地函式叫什麼名字?
2.2 只要服務端提供的js
指令碼是動態生成的就行了,呼叫者可以傳一個引數過去告訴服務端本地函式的名字,於是服務端就可以按照客戶的需求來生成js
指令碼並相應了。
var flightHandler = function (data) {
alert(`你查詢的航班結果是:票價 ` + data.price + `元,餘票` + data.tickets + `張。`);
};
var url = `http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler`;
var script = document.createElement(`script`);
script.setAttribute(`src`, url);
document.getElementsByTagName(`head`)[0].appendChild(script);
並沒有直接把遠端js
寫死,而是編碼事項動態查詢。這是JSONP
的核心部分。在呼叫的url
中傳遞了一個code
引數,告訴伺服器要查的是CA1998
次航班的資訊,而callback
引數告訴伺服器,本地呼叫的函式叫做flightHandler
。
伺服器的flightResult.aspx
生成了以下程式碼提供給頁面:
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
執行一下頁面,成功提示視窗,JSONP
的執行全過程順利完成。
2.3 jQuery
程式碼
$(function() {
$(`button`).on(`click`, function(event) {
event.preventDefault();
$.ajax({
type: `GET`,
async: false,
url: `http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998`,
dataType: `jsonp`,
jsonp: `callback`,
jsonpCallback: `flightHandler`, // 預設為jQuery自動生成的隨機函式名
success: function (json) {
alert(`你查詢的航班結果是:票價 ` + json.price + `元,餘票` + json.tickets + `張。`);
},
error: function () {
alert(`fail`);
}
});
});
});
jQuery
自動生成回撥函式並把資料取出來供success
屬性方法來呼叫。
三、JSONP
與Ajax
的關係
-
Ajax
與JSONP
這兩種技術看起來很像,目的也一樣,都是請求一個url
,然後把伺服器返回的資料進行處理,因此jQuery
等框架都把JSONP
作為Ajax
的一種形式。 -
實際上
Ajax
與JSONP
有著本質上的不同。Ajax
的核心是通過XMLHttpRequest
獲取資料,而JSONP
的核心則是動態新增<script>
標籤來呼叫伺服器提供的js
檔案。 -
Ajax
與JSONP
的區別也不在於是否跨域,Ajax
通過服務端代理也可以跨域,JSONP
也可獲取同源資料。