在前端的JS請求中,跨域的問題經常存在,根據不同的實現原理,常見的跨域的方法如下:
一:前端的方式
1:在前端頁面中,可以直接引用跨域資源的標簽有三個,分別是img的src,style的href和script的src。這三個都可以直接引用外域的資源。
在img和style的請求中,可以直接通過請求的地址加后綴參數進行參數傳遞,但是沒有接受服務器返回的操作。
在script的src可以通過和服務器端的配合實現數據的傳遞與返回,稍后討論
2:其他前端的跨域方式
2.1:document.domain方式,同源策略,在考慮跨域問題的時候,如果兩個頁面擁有相同的主域但是子域不同,則可以通過document.domain的修改實現兩者相同域的實現。在修改的時候注意只能修改為與當前相同的域或者父級的域。而且必須是一個符合格式的domain。
2.2:window.name跨域
window對象有個name屬性,該屬性有個特征:即在一個窗口(window)的生命周期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,并不會因新頁面的載入而進行重置。
比如有一個www.domain1.com/receive.html頁面,需要通過receive.html頁面里的js來獲取另一個位于不同域上的頁面www.domain2.com/data.html里的數據。
data.html頁面里的代碼很簡單,就是給當前的window.name設置一個receive.html頁面想要得到的數據值。data.html里的代碼:
window.name="I am the data";
那么在receive.html頁面中,我們怎么把data.html頁面載入進來呢?顯然我們不能直接在a.html頁面中通過改變window.location來載入data.html頁面,因為我們想要即使receive.html頁面不跳轉也能得到data.html里的數據。答案就是在receive.html頁面中使用一個隱藏的iframe來充當一個中間人角色,由iframe去獲取data.html的數據,然后a.html再去得到iframe獲取到的數據。
充當中間人的iframe想要獲取到data.html的通過window.name設置的數據,只需要把這個iframe的src設為www.domain2.com/data.html就行了。然后a.html想要得到iframe所獲取到的數據,也就是想要得到iframe的window.name的值,還必須把這個iframe的src設成跟receive.html頁面同一個域才行,不然根據前面講的同源策略,receive.html是不能訪問到iframe里的window.name屬性的。這就是整個跨域過程。
2.3:postMessage
postMessage是Html5新增的處理跨域問題的API,postMessage(data,origin)接受兩個參數。
1.data:要傳遞的數據,html5規范中提到該參數可以是JavaScript的任意基本類型或可復制的對象,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數,所以我們在傳遞參數的時候需要使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js可以實現類似效果。
2.origin:字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略,所以可以不寫,這個參數是為了安全考慮,postMessage()方法只會將message傳遞給指定窗口,當然如果愿意也可以建參數設置為"*",這樣可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/"。
操作示例:
<div>
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://domain2.com/test.html"></iframe>
</div>
在domain1中通過如下方法調用postMessage接口
window.onload=function(){
window.frames[0].postMessage('getcolor','http://lslib.com');
}
接受的時候監聽Window的message事件:
window.addEventListener('message',function(e){
if(e.source!=window.parent) return;
var color=e.data;
console.log(e.data);
}
二:后端的方式
在后端處理的過程中,服務器通過Access-Control-Allow-Origin可以設置那些域可以訪問當前資源,如果要開放給所有的域訪問,則直接設置為*即可。
優點是瀏覽器端不用考慮同源策略的限制,缺點就是增加服務器的負擔,且訪問速度慢。
三:前后端的方式
這里涉及到的就是我們經常說道的JSONP的方式,JSONP是通過前后端配合的方式實現跨域的實現,前端采用的是基于Script的實現,通過動態的創建script標簽,將要請求數據的參數和回調函數寫在src 的參數中。服務器收到請求之后,按照對應的參數和回調函數返回對應的結果,
示例如下:
假如當前我們的網站www.our.com想獲取12306的某一輛車的余票情況,我們客戶端如下構造:
function getInfoCallback(data){
console.log(data);
}
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src="http://www.12306.com/getLeftTicket?id=k58&callback=getInfoCallback;
然后12306那邊按照我們傳遞的參數和回調函數返回如下的script內容:
getInfoCallback({
id: "k58",
left: 123
})
當script收到返回的內容相當于直接調用當前頁面的函數,以此可以達到跨域的功能。