淺談跨域(一)——影象Ping和JSONP
在CORS技術出現以前,要實現Ajax跨域通訊是比較困難的。開發人員們想出了一些辦法,利用DOM中能夠執行跨域請求的功能,在不依賴XHR物件的情況下也能傳送某種請求。例如影象ping和JSONP。
影象Ping
我們知道,一個網頁可以從任何網頁載入影象,不用擔心跨域不跨域,所以,我們就可以利用圖片不受“同源限制”這一點進行跨域通訊。
我們利用JS建立一個新的Image物件,並把src屬性設定為指向請求的地址,通過監聽onload和onerror事件來確定是否接受到了響應。響應的資料可以是任意內容,但通常是畫素圖或204響應。
需要注意的是,新影象元素只要設定了src屬性就會開始下載,所以我們這裡的事件一定要在指定src屬性之前繫結,這也是為什麼我們這裡不需要把img標籤插入DOM 的原因。
<body>
<button id="Ping">影象Ping傳送請求</button>
<script>
var btn=document.getElementById('Ping');
btn.onclick=function () {
var img=new Image();
img.onload=img.onerror=function () {
alert("Done");
};
img.src="http://localhost:8081/img?name=Joy" ;
}
</script>
</body>
//伺服器程式碼
app.get('/img',function (req,res) {
res.send("我是一張圖片");
});
這種方式優點是很明顯的:相容性非常好,缺點就是:只能發生GET請求,而且無法獲取響應文字。
JSONP
利用動態指令碼插入技術,動態建立script標籤,同樣是利用src屬性,向指定URL發出請求。也就是說,伺服器返回的資料就是要插入文件的js程式碼。在客戶端監聽onload和onerror事件。
這裡要注意的是,不同於img元素,script標籤要插入文件後才開始下載。
jsonp由兩部分組成:回撥函式和資料。回撥函式是當響應到來時用該在與面呼叫的函式,資料是由伺服器填充的傳入回撥函式的json資料,就像下面這樣:
callback({"name":"Joy"})
<body>
<button id="jsonp">jsonp傳送請求</button>
<div id="result"></div>
<script>
var btn=document.getElementById('jsonp');
function handleResponse(response) {
document.getElementById("result").innerHTML=response;
};
btn.onclick=function () {
var script=document.createElement("script");
script.src="http://localhost:8081/script?callback=handleResponse";
document.body.appendChild(script);
}
</script>
</body>
//服務端程式碼
app.get('/script',function (req,res) {
res.send("handleResponse('我是從伺服器傳來的資料')")
});
相比於影象Ping,JSONP的優勢在於:可以能夠直接訪問響應文字,支援在瀏覽器和伺服器之間的雙向通訊。 缺點是:JSONP直接從其他域載入程式碼執行,如果其他域不安全,可能會在響應中夾帶一些惡意程式碼。其次,要確定JSONP請求是否失敗並不容易,HTML5為script增加了onerror方法,但是目前支援度還不是很好。