跨域產(chǎn)生的原因
JavaScript出于安全方面的考慮棒动,不允許跨域調(diào)用其他頁面的對象,其實就是因為JavaScript同源策略的限制宾添,只有同一域名下船惨,或者同一域名的不同文件夾之間允許通信.
當(dāng)兩個域具有相同的協(xié)議, 相同的端口,相同的host缕陕,就可以認(rèn)為它們是相同的域
同源策略
同源策略是一個很重要的安全理念粱锐,它在保證數(shù)據(jù)的安全性方面有著重要的意義。同源策略規(guī)定跨域之間的腳本是隔離的榄檬,一個域的腳本不能訪問和操作另外一個域的絕大部分屬性和方法
同源策略雖然安全但卻影響了跨域資源共享卜范,所以在跨域請求上就產(chǎn)生了很多寶貴經(jīng)驗.
跨域資源共享(CORS)
定義了必須在訪問跨域資源時,瀏覽器與服務(wù)器應(yīng)該如何溝通鹿榜。CORS的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通海雪,從而決定請求或響應(yīng)是應(yīng)該成功還是失敗
瀏覽器將CORS請求分成兩類:簡單請求(simple request
)和非簡單請求(not-so-simple request
)
服務(wù)器端對于CORS的支持,主要就是通過設(shè)置Access-Control-Allow-Origin來進(jìn)行的舱殿。如果瀏覽器檢測到相應(yīng)的設(shè)置奥裸,就可以允許Ajax進(jìn)行跨域的訪問
目前的跨域方法
跨域資源共享分為單向跨域和雙向跨域
一、通過JSONP(JSON with Padding)跨域
在js中沪袭,我們直接用XMLHttpRequest請求不同域上的數(shù)據(jù)時湾宙,是不允許的。但是冈绊,在頁面上引入不同域上的js腳本文件卻是可以的侠鳄,我們可以通過script標(biāo)記來動態(tài)加載其他域的資源,JSONP就是利用這個特性來實現(xiàn)的.
JSONP由兩部分組成:回調(diào)函數(shù)和數(shù)據(jù)死宣∥岸瘢回調(diào)函數(shù)是當(dāng)響應(yīng)到來時應(yīng)該在頁面中調(diào)用的函數(shù)博秫,而數(shù)據(jù)就是傳入回調(diào)函數(shù)中的JSON數(shù)據(jù)
優(yōu)點:
- JSONP屬于單向跨域
- 簡單高效挡育,易于實現(xiàn)
- 兼容性好巴碗,大部分瀏覽器都可運行
缺點:
- 執(zhí)行第三方的腳本存在安全隱患,適合受信任的雙方使用
- 支持GET請求而不支持POST等其它類型的HTTP請求
- 只支持跨域HTTP請求這種情況明垢,不能解決不同域的兩個頁面之間如何進(jìn)行JavaScript調(diào)用的問題
CORS和JSONP對比
- JSONP只能實現(xiàn)GET請求施绎,而CORS支持所有類型的HTTP請求
- 使用CORS,開發(fā)者可以使用普通的XMLHttpRequest發(fā)起請求和獲得數(shù)據(jù)俱尼,比起JSONP有更好的錯誤處理
- JSONP主要被老的瀏覽器支持,它們往往不支持CORS刃永,而絕大多數(shù)現(xiàn)代瀏覽器都已經(jīng)支持了CORS
二喧锦、使用window.name來進(jìn)行跨域
window對象有個name屬性束亏,該屬性在一個窗口(window)的生命周期內(nèi),窗口載入的所有的頁面都是共享一個window.name的涌穆,每個頁面對window.name都有讀寫的權(quán)限,window.name是持久存在一個窗口載入過的所有頁面中的祝沸,不會因新頁面的載入而進(jìn)行重置
我們可以在頁面A中用iframe加載其他域的頁面B卤唉,而頁面B中用JavaScript把需要傳遞的數(shù)據(jù)賦值給window.name,iframe加載完成之后痊硕,頁面A修改iframe的地址,將其變成同域的一個地址,然后就可以讀出window.name的值了.
優(yōu)點:
這個方式非常適合單向的數(shù)據(jù)請求,而且協(xié)議簡單、安全谴分,不會像JSONP那樣不限制地執(zhí)行
三薄翅、通過修改document.domain來跨子域
通過修改document的domain屬性舀奶,我們可以在域和子域或者不同的子域之間通信罗岖。同域策略認(rèn)為域和子域隸屬于不同的域,比如www.a.com和sub.a.com是不同的域桑包,這時南蓬,我們無法在www.a.com下的頁面中調(diào)用sub.a.com中定義的JavaScript方法蓖康。但是當(dāng)我們把它們document的domain屬性都修改為a.com,瀏覽器就會認(rèn)為它們處于同一個域下鳖悠,那么我們就可以互相調(diào)用對方的method來通信了
不過如果你想在http://www.example.com/a.html頁面中通過ajax直接請求http://example.com/b.html頁面胞皱,即使你設(shè)置了相同的document.domain也還是不行的,所以修改document.domain的方法只適用于不同子域的框架間的交互.
(修改document.domain屬于雙向跨域)
四萌朱、使用HTML5中新引進(jìn)的window.postMessage方法來跨域傳送數(shù)據(jù)
window.postMessage(message,targetOrigin)
方法是html5新引進(jìn)的特性宴树,可以使用它來向其它的window對象發(fā)送消息又憨,無論這個window對象是屬于同源或不同源,目前IE8+锭吨、FireFox蠢莺、Chrome,Opera等瀏覽器都已經(jīng)支持該方法
調(diào)用postMessage方法的window對象是指要接收消息的那一個window對象
該方法的第一個參數(shù)message為要發(fā)送的消息耐齐,類型只能為字符串浪秘;
第二個參數(shù)targetOrigin用來限定接收消息的那個window對象所在的域,如果不想限定域埠况,可以使用通配符 *
需要接收消息的window對象耸携,可以通過監(jiān)聽自身的message事件來獲取傳過來的消息,消息內(nèi)容儲存在該事件對象的data屬性中辕翰。上面所說的向其他window對象發(fā)送消息夺衍,其實就是指一個頁面有幾個框架的情況,因為每一個框架都有一個window對象喜命。不同域的框架間是可以獲取到對方的window對象的沟沙,也可以使用window.postMessage這個方法。
(window.postMessage屬于雙向跨域)
此外的跨域方式還有
-
flash (單向壁榕,雙向)
借助flash發(fā)送http請求
Flash LocalConnection(雙向) -
server proxy(單向)等