0、關于JSONP
什麼的JSONP
JSONP(JSON with Padding)是資料格式 JSON 的一種“使用模式”,可以讓網頁從别的網域要資料。另一個解決這個問題的新方法是跨來源資源共享。(參考:https://zh.wikipedia.org/wiki/JSONP)
JSONP的起源
- 曾經的Ajax不能跨域請求(現在的也不能,不過有cors)
- Web上使用script調用js檔案不存在跨域問題(實際上,隻要擁有src屬性的标簽都允許跨域,比如script,img,iframe)
- 那個時候,想要通過web端跨域通路資料,隻可以在伺服器端設法把資料裝進js,然後用戶端調用
- 剛好這個時候JSON大行其道
- 是以,解決方案就出來,web端像調用腳本一樣來跨域請求伺服器上動态生成的js檔案
- 為了便于用戶端使用資料,逐漸形成了一種非正式傳輸協定,人們把它稱作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伺服器允許跨域的一種設定)。