摘要:瀏覽器同源政策以及跨域同源是指協(xié)議相同域名相同端口相同。同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。該協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。參考文獻(xiàn)瀏覽器同源政策及其規(guī)避方法詳解跨域問(wèn)題
瀏覽器同源政策以及JS跨域
同源是指協(xié)議相同、域名相同、端口相同。同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
同源策略主要限制下面三種情況
Cookie 無(wú)法讀取
DOM 無(wú)法獲得
AJAX 請(qǐng)求不能發(fā)送
同源策略的本意是為了保證用戶的信息安全。但有時(shí)也會(huì)帶來(lái)不便,下面我們來(lái)看一下怎樣規(guī)避同源的限制。
Cookie是服務(wù)器寫(xiě)入瀏覽器的一小段信息,只有同源的網(wǎng)頁(yè)才能共享。
當(dāng)兩個(gè)網(wǎng)頁(yè)的一級(jí)域名相同,只是二級(jí)域名不同的時(shí)候,我們可以通過(guò)設(shè)置document.domain來(lái)共享cookie
具體操作如下:
// 這兩個(gè)網(wǎng)頁(yè)的一級(jí)域名是相同的 http://h1.test.com http://h2.test.com //為兩個(gè)頁(yè)面設(shè)置相同的 document.domain document.domain = "test.com" // 這樣兩個(gè)網(wǎng)頁(yè)就能共享`Cookie`
document.domain 不能隨意設(shè)置,只能把document.domain設(shè)置成自身或更高一級(jí)的父域。
跨域文檔通信如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM,也無(wú)法進(jìn)行通信。典型的例子是iframe窗口和window.open方法打開(kāi)的窗口,它們與父窗口無(wú)法通信。
如果兩個(gè)窗口一級(jí)域名相同,只是二級(jí)域名不同,那么設(shè)置上一節(jié)介紹的document.domain屬性,就可以規(guī)避同源政策,拿到DOM。
關(guān)于通信,我們來(lái)看一下兩種解決方案:
片段識(shí)別符片段標(biāo)識(shí)符(fragment identifier)指的是,URL的#號(hào)后面的部分,如果只是改變片段標(biāo)識(shí)符,頁(yè)面不會(huì)重新刷新。
//父窗口可以把信息,寫(xiě)入子窗口的片段標(biāo)識(shí)符 var src = originURL + "#" + data; document.getElementById("myIFrame").src = src; //子窗口通過(guò)監(jiān)聽(tīng)hashchange事件得到通知 window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // ... } //同樣的,子窗口也可以改變父窗口的片段標(biāo)識(shí)符 parent.location.href= target + "#" + hash;window.postMessage
window.postMessage 是HTML5為了解決這個(gè)問(wèn)題,引入了一個(gè)全新的API,無(wú)論兩個(gè)窗口是否同源,都允許一個(gè)窗口向另一個(gè)窗口發(fā)送數(shù)據(jù)。
語(yǔ)法:
// otherWindow 其他窗口的一個(gè)引用,比如iframe的contentWindow屬性、執(zhí)行window.open返回的窗口對(duì)象 //message 將要發(fā)送到其他 window的數(shù)據(jù) //targetOrigin 接收消息的窗口的源(origin) otherWindow.postMessage(message, targetOrigin)
其他window可以監(jiān)聽(tīng)message
//監(jiān)聽(tīng) message 事件 window.addEventListener("message", receiveMessage, false); //事件對(duì)象有一些常用的屬性 //data 從其他 window 中傳遞過(guò)來(lái)的對(duì)象 //origin 消息發(fā)送方窗口的 origin //source 對(duì)發(fā)送消息的窗口對(duì)象的引用 function receiveMessage(event){ var origin = event.origin; //對(duì)發(fā)送消息的源進(jìn)行驗(yàn)證 if (origin !== "http://example.org:8080") return; // ... }
實(shí)例:
窗口A : http://xiaoxiong.com
窗口B : http://miaomiao.com
顯然這兩個(gè)窗口不同源,不能通信,現(xiàn)在我們用postMessage進(jìn)行通信。
//Awindow、Bwindow分別表示對(duì) A B 窗口對(duì)象的引用 //B窗口向A窗口發(fā)消息 //如果A窗口的協(xié)議、主機(jī)地址或端口這三者的任意一項(xiàng)不匹配targetOrigin提供的值,消息就不能發(fā)送成功 //注意是用 Awindow 調(diào)用 postMessage 方法 Awindow.postMessage("hello!","http://xiaoxiong.com"); //在A中設(shè)置監(jiān)聽(tīng)事件 window.addEventListener("message", receiveMessage, false); function receiveMessage(event){ console.log(event.origin);//http://miaomiao.com console.log(event.source);// Bwindow console.log(event.data);// hello! }AJAX
AJAX請(qǐng)求是我們經(jīng)常用到的異步請(qǐng)求方法,但是AJAX請(qǐng)求是不能跨域的。
下面我們看一下常見(jiàn)的AJAX跨域方法
JSONP基本思想是,網(wǎng)頁(yè)通過(guò)添加一個(gè)