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服務器允許跨域的一種設置)。