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