跨域解決方案合集
瀏覽器的同源策略會導致跨域,這裡同源策略又分為以下兩種
1. DOM同源策略:禁止對不同源頁面DOM進行操作。這裡主要場景是iframe跨域的情況,不同域名的iframe是限制互相訪問的。
2. XmlHttpRequest同源策略:禁止使用XHR物件向不同源的伺服器地址發起HTTP請求。
只要協議、域名、埠有任何一個不同,都被當作是不同的域,之間的請求就是跨域操作。
解決方式:
針對DOM不同源:
1. document.domain
2. Location.hash
3. postMessage
針對XmlHttpRequest不同源:
1. 跨域資源共享 CORS
*
* 實現CORS通訊的關鍵是伺服器,只要伺服器實現了CORS介面,就可以實現跨源通訊
* CORS請求分為:簡單請求 & 非簡單請求
* 伺服器相應中CORS相關欄位都帶 Access-Control- 開頭
* 客戶端中 withCredentials 屬性
2. jsonp
* 只支援GET請求,支援老式瀏覽器,可以向不支援CORS的網路請求資料
3. 伺服器代理
Jsonp:
JSONP是一種非正式傳輸協議,該協議的一個要點就是允許使用者傳遞一個callback引數給服務端,然後服務端返回資料時會將這個callback引數作為函式名來包裹住JSON資料,這樣客戶端就可以隨意定製自己的函式來自動處理返回資料了。JSONP只能是get請求,script也是一種get請求,利用script標籤沒有跨域限制的特性來達到與第三方通訊的目的,第三方產生的響應為json資料的包裝(jsonp,json padding),即後端輸出的response text必須符合js語法
//方式1 //這種方式無法對請求進行錯誤處理 var script = document.createElement("script"); script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild); //方式2 $.ajax({ url: 'https://api.douban.com/v2/book/search?callback=handleResponse', data: { q: 'javascript', count: 1 }, jsonp: 'callback',//傳遞給請求處理程式或頁面的,用以獲得jsonp回撥函式名的引數名(一般預設為:callback) dataType: 'jsonp',//自定義的jsonp回撥函式名稱,預設為jQuery自動生成的隨機函式名,也可以不寫,jQuery會把資料拿出來放到success函式的引數裡 jsonpCallback: 'handleResponse', success (data){ console.log(data); }, error (XMLHttpRequest, textStatus, errorThrown){ console.error(XMLHttpRequest, textStatus, errorThrown) } }); //方式3(僅介面是.json字尾才可以跨域,即訪問遠端json檔案) $.getJSON("GetUserbyName.aspx?name=ww&callback=?", function(date){ //.... } )
- html標籤的src屬性沒有同源限制(支援跨域),瀏覽器解析script標籤時,會自動下載src屬性值(url)指向的資源;
- script標籤指向的資原始檔被下載後,其中的內容會被立即執行;伺服器端的程式會解析src屬性值中的url傳遞的引數,根據這些引數針對性返回一個/多個函式呼叫表示式,這些函式呼叫表示式的引數就是客戶端跨域想得到的資料;
- 伺服器生成、返回的檔案中,表示式呼叫的函式是已經在本地提前定義好的,而引數就是希望從跨域伺服器拿到的資料。
- 字面的script標籤可以,動態新增到dom樹中的script也可以,後者更方便繫結事件。
- img link iframe 等元素都可以傳送跨域請求
- 只支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript呼叫的問題。
document.domain
用document.domain來指定域有侷限性,也就是一級域名一致才可以
www.sojson.com 下指到 sojson.com 是可以的。
icp.sojson.com 下指到 sojson.com 是可以的。
www.sojson.com 下指到 www.baidu.com 是不行的。
sojson.com 指到 baidu.com 還是不行的。
在需要通訊的兩個域中都寫下如下程式碼:
if(document.domain != 'sojson.com'){
document.domain = 'sojson.com';
}
保證一致即可
一級域名 有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。
二級域名 是指增加了一級,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com 等等
document.domain
用document.domain來指定域有侷限性,也就是一級域名一致才可以
www.sojson.com 下指到 sojson.com 是可以的。
icp.sojson.com 下指到 sojson.com 是可以的。
www.sojson.com 下指到 www.baidu.com 是不行的。
sojson.com 指到 baidu.com 還是不行的。
在需要通訊的兩個域中都寫下如下程式碼:
if(document.domain != 'sojson.com'){
document.domain = 'sojson.com';
}
保證一致即可
一級域名 有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。
二級域名 是指增加了一級,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com 等等
location.hash
通過把資料寫在url的#號後面來傳遞資料。a.com 裡的頁面 a1.html巢狀 b.com 的 b1.html,b1.html 修改 parent.hash,a1.html 監聽 hashchange 來實現。(ie、chrome的安全機制無法修改parent.location.hash,所以要利用一箇中間的 a.com 域下的代理iframe,即在 b1.html 中增加一個 iframe,src為 a.com 域下的頁面)
利用hash跨域,資料直接暴露在了url中,資料容量和型別都有限
//a1.html
function startRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
document.body.appendChild(ifr);
}
function checkHash() {
try {
var data = location.hash ? location.hash.substring(1) : '';
if (console.log) {
console.log('Now the data is '+data);
}
} catch(e) {};
}
setInterval(checkHash, 2000);
//b1.html 模擬一個簡單的引數處理操作
switch(location.hash){
case '#paramdo':
callBack();
break;
case '#paramset':
//do something……
break;
}
function callBack(){
try {
parent.location.hash = 'somedata';
} catch (e) {
// ie、chrome的安全機制無法修改parent.location.hash,
// 所以要利用一箇中間的cnblogs域下的代理iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata'; // 注意該檔案在"a.com"域下
document.body.appendChild(ifrproxy);
}
}
//a2.html
//因為parent.parent和自身屬於同一個域,所以可以改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);