摘要:但是這種方法適用于和窗口,和無(wú)法通過(guò)這種方法規(guī)避同源策略。逗號(hào)分隔的一個(gè)字符串,表明服務(wù)器支持的所有跨域請(qǐng)求的方法。
同源策略在制作oneday-music-player的時(shí)候要使用ajax向百度音樂(lè)的api發(fā)送請(qǐng)求,然后出現(xiàn)了XMLHttpRequest cannot load "http://...." . No "Access-Control-Allow-Origin" header is present on the request resource. Origin "http://...." is therefore not allowed access,經(jīng)過(guò)搜索發(fā)現(xiàn)是受到了同源策略的影響而導(dǎo)致的跨域問(wèn)題,所以學(xué)習(xí)一下關(guān)于跨域的知識(shí)點(diǎn)。
同源策略限制從一個(gè)源加載的文檔或腳本與另一個(gè)源的文檔或腳本進(jìn)行交互的方式,是隔離潛在惡意文件的重要安全機(jī)制。
兩個(gè)頁(yè)面擁有同樣的協(xié)議、端口(如果指定)和域名時(shí),可以說(shuō)兩個(gè)頁(yè)面是同源的。
下表是相對(duì)于http://store.company.com/dir/page.html同源檢測(cè)的示例:
url | 結(jié)果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | 成功 | |
http://store.company.com/dir/inner/other.html | 成功 | |
https://store.company.com/secure.html | 失敗 | 不同協(xié)議(https和http) |
http://store.company.com:81/dir/etc.html | 失敗 | 不同端口(81和80) |
http://news.company.com/dir/other.html | 失敗 | 不同域名(news和store) |
而如果非同源,則有三種行為會(huì)受到限制:
Cookie、LocalStorage和IndexDB無(wú)法讀取
DOM無(wú)法獲得
AJAX請(qǐng)求不能發(fā)送
規(guī)避同源策略(跨域) Cookie document.domainCookie是服務(wù)器寫(xiě)入瀏覽器的一小段信息,只有同院的網(wǎng)頁(yè)才能共享。但是,兩個(gè)網(wǎng)頁(yè)一級(jí)域名相同,只是二級(jí)域名不同,瀏覽器允許通過(guò)document.domain共享Cookie
例如,假設(shè)文檔中的一個(gè)腳本在http://store.company.com/dir/page.html執(zhí)行以下語(yǔ)句:
document.domain = "company.com"
此時(shí),http://news.company.com/dir/other.html和http://store.company.com/dir/other.html
就可以通過(guò)document.cookie來(lái)設(shè)置或獲取Cookie,即共享Cookie。
但是這種方法適用于Cookie和iframe窗口,LocalStorage和IndexDB無(wú)法通過(guò)這種方法規(guī)避同源策略。
iframe如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM,典型的例子是iframe窗口和window.open方法打開(kāi)的窗口,如果和父窗口不同源,則會(huì)報(bào)錯(cuò)。
此時(shí)如果兩個(gè)窗口一級(jí)域名相同,只是二級(jí)域名不同,那么設(shè)置document.domain屬性,就可以規(guī)避同源策略。
而對(duì)于完全不同源的網(wǎng)站,目前有三種方法可以解決跨域窗口之間的通信問(wèn)題。
片段標(biāo)識(shí)符(fragment identifier)
window.name
跨文檔通信API(cross-document messaging)
片段標(biāo)識(shí)符片段標(biāo)識(shí)符(fragment identifier)指的是URL的#后面的部分,即http://store.company.com/dir/other.html#fragment的#fragment(location.hash),如果只改變片段標(biāo)識(shí)符,頁(yè)面不會(huì)重新刷新。
父窗口可以把信息寫(xiě)入子窗口的片段標(biāo)識(shí)符,子窗口通過(guò)監(jiān)聽(tīng)hashchange事件得到通知。
window.name每個(gè)iframe都有包裹它的window,這個(gè)window是top window的子窗戶,所以自然有window.name屬性,指的是當(dāng)前窗口的名字,這個(gè)屬性的最大特點(diǎn)是,無(wú)論是否同源,只要在同一個(gè)窗口里,窗口內(nèi)所有頁(yè)面對(duì)window.name都有讀寫(xiě)的權(quán)限。
window.name的值只能是字符串的形式,這個(gè)字符串的最大能允許2M左右甚至更大的一個(gè)容量,具體取決于不同的瀏覽器。
例如,想要在http://example/a.html中獲取http://company.com/data.html中的數(shù)據(jù),可以在a.html中使用一個(gè)隱藏的iframe,將iframe的src首先設(shè)置為http://company.com/data.html,將其window.name設(shè)置為所需的數(shù)據(jù)內(nèi)容,隨后再將這個(gè)iframe的src設(shè)置為跟a.html頁(yè)面同一個(gè)域的一個(gè)頁(yè)面,不然a.html獲取不到該iframe的window.name
window.postMessage這是html5中新引入的一個(gè)API,可以使用它向其它的window對(duì)象發(fā)送消息,無(wú)論這個(gè)window對(duì)象屬于同源還是不同源。
例如,父窗口http://example/a.html向子窗口http://company.com/data.html發(fā)送消息:
var newWin = window.open("http://company.com/data.html", "title") newWin.postMessage("Hello World!". "http://company.com/data.html")
window.postMessage方法的第一個(gè)參數(shù)是具體的信息內(nèi)容,第二個(gè)參數(shù)是接收消息的窗口的源,即協(xié)議+端口+域名,也可以設(shè)置為*,表示不限制域名。
子窗口向父窗口發(fā)送消息的寫(xiě)法類似:
window.opener.postMessage("Nice to see you", "http://example/a.html")
子窗口和父窗口都可以通過(guò)message時(shí)間,監(jiān)聽(tīng)對(duì)方的消息。
window.addEventListener("message", function(e) { // ... }, false)
message事件的事件對(duì)象event有以下三個(gè)屬性:
event.source: 發(fā)送消息的窗口
event.origin: 消息發(fā)向的網(wǎng)址(可以限制目標(biāo)網(wǎng)址)
event.data: 消息內(nèi)容
通過(guò)window.postMessage,也可以讀寫(xiě)其他窗口的localStorage
AJAX同源策略規(guī)定,AJAX請(qǐng)求只能發(fā)給同源的網(wǎng)址,否則就報(bào)錯(cuò),但是有三種方法可以規(guī)避這個(gè)限定:
JSONP
WebSocket
CORS
JSONPJSONP是服務(wù)器與客戶端跨源通信的常用方法。基本思想是利用