摘要:什么是跨域我們先看下以下場景開啟兩個本地服務(wù)器,頁面為,其中嵌套了,頁面想使用頁面的數(shù)據(jù),例如調(diào)用它的方法,會報以下錯誤如圖所示,,,譯為協(xié)議主機(jī)和端口號必須符合,否則,就是跨域。跨域的幾種常見方案同源策略的限制范圍有以下幾種和無法讀取。
什么是跨域
我們先看下以下場景:
開啟兩個本地服務(wù)器,頁面A為localhost:9800,其中嵌套了iframeB localhost:9000,頁面A想使用頁面B的數(shù)據(jù),例如調(diào)用它的方法,會報以下錯誤
如圖所示,Protocols,domains,and ports must match. 譯為:協(xié)議、主機(jī)和端口號必須符合,否則,就是跨域。
下面我們來具體談?wù)劇?/p> 瀏覽器的同源策略
我們都知道,瀏覽器有個同源策略,也就是這個策略,限制了兩個源中的資源相互交互。
Two pages have the same origin if the protocol, port (if one is specified), and host are the same for both pages.譯為:如果兩個頁面有相同的協(xié)議、端口號和主機(jī),那么這兩個頁面就屬于同一個源。
也就是說,只有同一個源才可以進(jìn)行資源共享。
我們來舉幾個例子,如果想和 http://www.test.com/index.html 進(jìn)行通信:
URL | Result | Reason |
---|---|---|
http://www.test.com/page/othe... | 允許 | |
http://www.test.com/index.js | 允許 | |
http://a.test.com/index.html | 不允許 | 子域不同 |
http://www.other.com/index.html | 不允許 | 主域不同 |
https://www.test.com/index.html | 不允許 | 協(xié)議不同 |
http://www.test.com:3000/index.html | 不允許 | 端口不同 |
我們可以看到,協(xié)議、端口、主機(jī)缺一不可,必須完全匹配,上文就是由于端口號不同而報錯。
那為什么要有同源策略的限制呢?原因也很簡單,就是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
試想一下,如果我們可以隨意訪問一個網(wǎng)站的cookie,那么豈不是隨意竊取別別人登陸的cookie?如果沒有同源策略,那互聯(lián)網(wǎng)就太危險了。
跨域的幾種常見方案同源策略的限制范圍有以下幾種:
Cookie、LocalStorage 和 IndexDB 無法讀取。
DOM 無法獲得。
AJAX 請求不能發(fā)送。
而跨域訪問,也無非兩種情況:一是請求不同源下的接口(如上第3種);二是請求不同源的頁面的資源(如上1、2,通常是頁面中嵌套不同源的iframe要進(jìn)行通信)。本文主要討論第二種情況下造成的跨域,方法很多,主要介紹以下幾種:document.domain、location.hash、window.name、postMessage。
document.domain適用于:主域相同子域不同的頁面,例如上例中的第三種
方法:只需將這兩個頁面的document.domain設(shè)置為相同的父域名,即可實現(xiàn)不同子域名之間的跨域通信。
location.hash
一般來說,URL的任何改變都重新會加載一個新的網(wǎng)頁,除了hash的變化,hash的任何改變都不會導(dǎo)致頁面刷新。
在跨域解決方案中,hash也非常有用,來自不同源的頁面可以相互設(shè)置對方的 URL,包括hash值,但不能獲取對方的hash值。文檔之間可以通過hash來相互通信。
流程(如上圖):
主頁面A中嵌入iframeB,兩個來自不同域
在主頁面A中,將想要傳遞給B的字段,作為hash,將它與B的url連接起來,然后將B的src設(shè)置為連接后的url
在iframeB中,就可以通過獲取自己url的hash值,從而得到主頁面?zhèn)鬟f的值,但在iframeB中,需設(shè)置一個定時器監(jiān)聽hash值的變化
除了設(shè)置定時器,還可以通過監(jiān)聽window.onhashchange事件
例子:啟動兩個本地服務(wù)器,主頁面localhost:9800,子頁面localhost:9000,主頁面向子頁面發(fā)消息
結(jié)果如下:點(diǎn)擊button后,子頁面將收到主頁面的消息
注意:使用hash時最好對其進(jìn)行編碼、解碼,否則在Firefox中會報錯。因為Firefox會自動將hash值進(jìn)行編碼,如果不進(jìn)行解碼就無法JSON.parse().
兩個頁面不同源的情況下,IE、Chrome不允許修改parent.location.hash的值(Firefox可以),所以如果主頁面想從子頁面獲取消息,只能借助一個代理iframe設(shè)置。
流程如下(兩種):
子頁面創(chuàng)建隱藏的代理iframe,與主頁面同源,并將消息作為hash,設(shè)置到iframe的src中
代理頁面將主頁面的hash值設(shè)置為自身的hash
主頁面使用定時器監(jiān)聽hash的變化
例子如下
結(jié)果如圖:
這種方法的劣處就是將消息暴露在url中,因此也可以采用下文將講述利用代理iframe跨域的方法,這邊就不贅述了。
由于現(xiàn)在許多網(wǎng)站的hash已經(jīng)被用于其他用途,此時想用hash跨域就會比較復(fù)雜了。這種情況下,我們可以使用一個同域的代理頁面來完成
頁面A想向頁面B發(fā)送數(shù)據(jù),流程如下:
頁面A創(chuàng)建一個隱藏的代理iframeC,這個iframe與頁面B同域
頁面A中,將要發(fā)送的數(shù)據(jù),作為hash,與頁面C的url連接起來
在代理iframeC中,它與B同域,可以直接調(diào)用頁面B中的方法,這樣便可以將hash值傳遞給B了
例子如下
結(jié)果如下:
缺點(diǎn):
數(shù)據(jù)直接暴露在url中,安全性較低
url大小是有限制的,它支持傳遞的數(shù)據(jù)量較小
window.name加載任何頁面 window.name 的值始終保持不變
當(dāng)頁面A想從頁面B中獲取數(shù)據(jù)時:
頁面A,創(chuàng)建一個隱藏的iframeC,將C的src指向頁面B
頁面C加載完成后,把響應(yīng)的數(shù)據(jù)附加到window.name上
C 取到數(shù)據(jù)后,將src設(shè)為任何一個與A同源的頁面,這時 A 就能獲取到 B 的name屬性值
A 取到數(shù)據(jù)后,隨時可以刪掉 C
例子,啟動兩個本地服務(wù)器,頁面Alocalhost:9800,頁面Blocalhost:9000,頁面A想從頁面B中獲取數(shù)據(jù)
結(jié)果如圖
另外,兩個頁面還可相互通信
頁面A通過hash,將數(shù)據(jù)傳遞給頁面B,頁面B仍通過window.name向頁面A傳遞數(shù)據(jù)
場景如下:頁面B存儲了一些人的信息,頁面B通過頁面A的輸入,獲取不同人的信息
輸入想獲得的數(shù)據(jù)的id值,即可得到相應(yīng)的信息
總結(jié):
優(yōu)點(diǎn):容量很大,可以放置很長的字符串(2M左右,比url大得多)
缺點(diǎn):必須要監(jiān)聽window.name屬性的變化
HTML5規(guī)范中的新方法window.postMessage()可以用于安全跨域通信。當(dāng)該方法調(diào)用時,將分發(fā)一個消息事件。對應(yīng)的窗口通過事件監(jiān)聽來獲取消息。
語法 :otherWindow.postMessage(message, targetOrigin)
otherWindow代表其他窗口的引用,例如iframe的contentWindow屬性,通過window.open返回的窗體,通過window.frames[]返回的ifame對象。
message表示發(fā)送給其他窗口的數(shù)據(jù)
targetOrigin指定哪些來源的窗口可以接收到消息事件,其值可以是字符串"*"(表示無限制)或"/"(表示與父窗口同源)或一個URI。發(fā)送消息時,只有目標(biāo)窗口的協(xié)議、主機(jī)、端口這三項都匹配targetOrigin提供的值,消息才會發(fā)送。
接收消息的窗口可以通過監(jiān)聽message事件,去接收消息
window.addEventListener("message", receiveMessage, false);
receiveMessage為接收到消息后的操作
message事件的事件對象event,提供三個屬性:
event.source:發(fā)送消息的窗體(可以用來引用父窗口)
event.origin:消息發(fā)向的網(wǎng)址(可以過濾不是發(fā)給本窗口的消息)
event.data:消息內(nèi)容
例子:啟動兩個本地服務(wù)器,頁面Alocalhost:9800,頁面Blocalhost:9000,頁面A根據(jù)頁面B發(fā)來的數(shù)據(jù)改變顏色
結(jié)果如下:點(diǎn)擊按鈕后,頁面的div由灰變藍(lán)
結(jié)語關(guān)于跨域的就先聊到這啦~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88072.html
摘要:如果像本例中這樣的場景會遇到這樣一個問題,詳見鏈接當(dāng)請求參數(shù)過長或為了安全,就需要用到下載。寫到這里自己都忍不住想錘自己,給自己挖坑不說,這樣來回請求下載,流量,真的是敗家。 這幾天一直在做遠(yuǎn)程文件下載的事,現(xiàn)在總算有了解決,特來記錄一下踩過的坑和想揍自己的心 需求 應(yīng)用場景是這樣的,底層邏輯數(shù)據(jù)請求接口是由Java寫的,也就是說原始文件存在Java服務(wù)端,返回時有加密措施 由于工作...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼什么是功能統(tǒng)計作為一名開發(fā),我們的產(chǎn)品發(fā)布出去之后,無論是產(chǎn)品還是運(yùn)營,其實都是想及時了解產(chǎn)品對用戶產(chǎn)生的影響的。下一章,我們將繼續(xù)聊聊速度統(tǒng)計。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/bl...
閱讀 3574·2023-04-26 00:05
閱讀 963·2021-11-11 16:55
閱讀 3541·2021-09-26 09:46
閱讀 3527·2019-08-30 15:56
閱讀 920·2019-08-30 15:55
閱讀 2947·2019-08-30 15:53
閱讀 1960·2019-08-29 17:11
閱讀 826·2019-08-29 16:52