摘要:在所有以上提到的跨域方法中,不得不說(shuō)都是利用了大大小小的漏洞來(lái)繞過(guò)同源策略。對(duì)于開(kāi)發(fā)者來(lái)說(shuō)最大的好處就是,無(wú)需考慮以什么樣的方式繞過(guò)同源策略請(qǐng)求跨域資源,直接使用即可。
HTML跨域 傳統(tǒng)跨域方式 JSONP跨域
說(shuō)到傳統(tǒng)跨域方式,JSONP是最廣泛為人所知的形式了。
對(duì)于JS來(lái)說(shuō),利用XMLHttpRequest無(wú)法請(qǐng)求非本域上的數(shù)據(jù),但是卻可以加載非本域的JS文件。
JSONP就是利用了這個(gè)所謂的“漏洞”。
試想當(dāng)我們?cè)谖臋n中插入一個(gè)script標(biāo)簽,請(qǐng)求一個(gè) JS 文件時(shí),該JS文件的內(nèi)容是直接調(diào)用一個(gè)函數(shù),
同時(shí)傳入適當(dāng)?shù)臄?shù)據(jù)。則對(duì)于方法內(nèi)部,就已經(jīng)可以通過(guò)參數(shù)的形式獲取傳入的數(shù)據(jù)。如下所示:
此處的對(duì)象,就是傳入的數(shù)據(jù),而fun則是那個(gè)函數(shù)。該函數(shù)其實(shí)可以是任意函數(shù)名,只需在我們的window域下定義,也可以根據(jù)需求定義在其他地方。問(wèn)題在于傳入的數(shù)據(jù)怎么來(lái)呢?其實(shí)這些對(duì)于前端來(lái)說(shuō)完全不用管,只需讓后端處理好后拼接成如上形式返回給我們即可。而fun里面放什么,則取決于你要對(duì)返回的數(shù)據(jù)做什么樣的處理了。
另外,fun的函數(shù)名建議是隨同跨域接口一起傳輸給server,以讓server來(lái)進(jìn)行拼接出合適的執(zhí)行代碼。完整代碼如下:
document.domain也許你會(huì)遇到這樣的情形:我的網(wǎng)頁(yè)內(nèi)嵌了一個(gè)iframe,該iframe所引用的頁(yè)面跟我本域不一樣,此時(shí)我想修改iframe中的內(nèi)容,該怎么辦呢?
或許你認(rèn)為可以通過(guò)contentWindow獲取iframe中的內(nèi)容,但很可惜的是我們拿到這個(gè)contentWindow,卻不能獲取到里面的屬性與方法(H5最新屬性postMessage除外,后面會(huì)提及)。
這是因?yàn)闉g覽器的同源策略禁止了我們這樣的操作,因?yàn)樗鼈兎謱俨煌脑础?/p>
此時(shí)就需要用到document.domain了,也就是我們只需將iframe中的document.domain設(shè)置成跟父頁(yè)面相同的值即可。
比如當(dāng) http://loliner.baidu.com/inde... 內(nèi)嵌了 http://baidu.com/example.html ,此時(shí)我們只需將 index.html 的 document.domain 修改成 baidu.com即可實(shí)現(xiàn)與example.html通信。
但是問(wèn)題來(lái)了,瀏覽器對(duì)document.domain的設(shè)置是有限制的,其只能設(shè)置成比自身域更高一級(jí)的域名,包括自身域。
比如存在http://b.a.com/index.html,則該頁(yè)面 document.domain允許的值為
b.a.com a.com
而c.b.a.com則是不允許的。且兩個(gè)頁(yè)面若要通訊,則兩者的主域必須相同。
上例中,主域就為 baidu.com。
window.name在一個(gè)窗口(window)的生命周期內(nèi),窗口載入的所有的頁(yè)面都是共享一個(gè)window.name,每個(gè)頁(yè)面對(duì)window.name都有讀寫(xiě)的權(quán)限。
以上是對(duì)window.name的定義。試想如果有兩個(gè)不同域的頁(yè)面順次被同一個(gè)窗口加載,那么對(duì)于這兩個(gè)頁(yè)面來(lái)說(shuō),兩者就能共享window.name,從而實(shí)現(xiàn)通信。
如何順次加載?利用window.location改變窗口的地址就可以辦到這一點(diǎn)。
比如,http://example.com/a.html 完全加載后,修改window.name為指定值。然后通過(guò)window.location將窗口定向到 http://loliner.com/b.html,此時(shí)b.html中window.name的值就為上一個(gè)頁(yè)面中設(shè)置的值。
window.name的值只能是一個(gè)字符串,最大2M,但對(duì)我們來(lái)說(shuō)已經(jīng)夠用了。如果你要傳遞對(duì)象或數(shù)組,進(jìn)行JSON格式化即可。
但是,雖然這樣實(shí)現(xiàn)了數(shù)據(jù)通信,但是我們不能來(lái)回這樣切來(lái)切去,那怎么辦呢?這時(shí)候就可以利用 iframe + contentWindow 了。
我們可以在 b.html 頁(yè)面添加一個(gè)隱藏的iframe,該iframe指向a.html,當(dāng)a.html完全加載并修改了window.name之后,我們將iframe重新指向與b.html在同一個(gè)域名下的c.html,此時(shí)就可以通過(guò) iframe 的 contentWindow 獲取到 name 的值了。
完整代碼如下:
H5跨域方式 window.postMessage我們知道在同一個(gè)頁(yè)面嵌入多個(gè)iframe,每個(gè)iframe的域都不一樣時(shí),雖然我們可以獲取iframe的window對(duì)象,卻不能訪問(wèn)其中的屬性和方法。但H5的最新屬性postMessage除外,那么我們是否可以在此利用這樣的一個(gè)“漏洞”來(lái)進(jìn)行跨域呢?
答案是可以的。
我們只需在iframe中設(shè)置onmessage監(jiān)聽(tīng),然后在父級(jí)頁(yè)面中獲取iframe的window對(duì)象,將父頁(yè)面所要傳遞的信息通過(guò)window.postMessage發(fā)出即可。
完整代碼如下:
首先要讓iframe監(jiān)聽(tīng)onmessage事件。
接下來(lái)則是在父頁(yè)面中獲取iframe的window對(duì)象并調(diào)用postMessage傳遞信息。
注意,此處的postMessage所發(fā)送的消息在低版本瀏覽器下只能為字符串,若要傳遞對(duì)象或數(shù)組,只能JSON格式化。
另外,第二個(gè)參數(shù)指的是域,表示你要將信息發(fā)送到哪個(gè)域,參數(shù)格式為協(xié)議+主機(jī)+端口,其實(shí)跟上面所說(shuō)document.domain的值是一回事。
CORS在所有以上提到的跨域方法中,不得不說(shuō)都是利用了大大小小的漏洞來(lái)繞過(guò)同源策略。而無(wú)論如何進(jìn)行繞過(guò),有一點(diǎn)可以肯定的是,WEB開(kāi)發(fā)當(dāng)中確實(shí)需要跨域獲取資源。
所以,W3C為我們制訂了 CORS 跨域訪問(wèn)機(jī)制。CORS對(duì)于開(kāi)發(fā)者來(lái)說(shuō)最大的好處就是,無(wú)需考慮以什么樣的方式繞過(guò)同源策略請(qǐng)求跨域資源,直接使用ajax即可。
那么誰(shuí)去負(fù)責(zé)跨域的安全性呢?答案是由Server進(jìn)行控制。
Server在接收到請(qǐng)求的時(shí)候,需判斷請(qǐng)求來(lái)源,如果該來(lái)源合法,返回正常數(shù)據(jù),同時(shí)需要在請(qǐng)求返回頭response header中添加必要 CORS 字段。
對(duì)于瀏覽器來(lái)說(shuō),若該請(qǐng)求的返回頭信息中,包含該 CORS 字段,那么瀏覽器就會(huì)正常讀取返回的信息,否則,就會(huì)拋出No "Access-Control-Allow-Origin" header is present on the requested resource.禁止跨域異常。
上面所說(shuō)到的CORS字段,分為必須與可選:
Access-Control-Allow-Origin(必須)
該服務(wù)器所允許跨域的源,如果為 * ,則表示允許所有源對(duì)該服務(wù)器進(jìn)行請(qǐng)求。
發(fā)送請(qǐng)求的一方的域,必須包含在該值所指定的源內(nèi)。
Access-Control-Allow-Credentials(可選)
表示是否允許發(fā)送cookie,該值為一個(gè)布爾值,默認(rèn)為false。
Access-Control-Expose-Headers(可選)
獲取response header中其他字段的值。
所以,簡(jiǎn)單的說(shuō),CORS 模式中的跨域請(qǐng)求其實(shí)與前端開(kāi)發(fā)者已經(jīng)沒(méi)有太大的關(guān)系,只要Server端控制好接口數(shù)據(jù),并按需寫(xiě)入CORS字段即可。
另外,CORS跨域請(qǐng)求可以分為簡(jiǎn)單請(qǐng)求與復(fù)雜請(qǐng)求。
簡(jiǎn)單請(qǐng)求對(duì)于簡(jiǎn)單請(qǐng)求,瀏覽器直接發(fā)送CORS請(qǐng)求即可,跟上面所說(shuō)流程一致。
HEAD、GET、POST都屬于簡(jiǎn)單請(qǐng)求。復(fù)雜請(qǐng)求
對(duì)于復(fù)雜請(qǐng)求,則需要首先發(fā)出預(yù)檢請(qǐng)求,判斷是否可以跨域,然后再發(fā)送真實(shí)請(qǐng)求。
PUT和DELETE,或Content-Type字段類(lèi)型為application/json的都屬于復(fù)雜請(qǐng)求。
就目前來(lái)說(shuō),JSONP 及 CORS 算是最常用的跨域形式了,也能滿(mǎn)足我們的絕大部分需求。
相對(duì)于JSONP,CORS W3C規(guī)定的標(biāo)準(zhǔn)跨域方式,功能更強(qiáng)大,安全性也更好。
JSONP只支持GET請(qǐng)求,而 CORS 支持多種請(qǐng)求。
JSONP 沒(méi)有域的概念,CORS 則有精確的指定哪些域可以獲取資源。
CORS 將域的安全性管理完全交給Server管理,更加安全。
Flash跨域Flash跨域也有多種形式,此處只介紹最常用的 crossdomain.xml 策略文件 模式及allowDomain 權(quán)限授予。
corssdomain.xml 跨域策略文件
與 CORS 復(fù)雜請(qǐng)求一樣,F(xiàn)lash在進(jìn)行跨域請(qǐng)求時(shí),默認(rèn)首先會(huì)發(fā)送預(yù)檢請(qǐng)求,判斷本域是否合法。該預(yù)檢請(qǐng)求會(huì)去跨域請(qǐng)求的根目錄獲取 corssdomain.xml 文件,該文件包含了跨域策略信息。比如最重要的一點(diǎn),就是告訴Flash哪些域可以跨域請(qǐng)求該服務(wù)器。
舉個(gè)栗子,http://baidu.com/a.html下有某swf文件要向http://loliner.com/請(qǐng)求資源。此時(shí)會(huì)經(jīng)過(guò)如下步驟:
Flash發(fā)現(xiàn)請(qǐng)求需要跨域,則首先請(qǐng)求http://loliner.com/crossdomai...文件;
若crossdomain.xml文件能正常返回,則分析其中的策略,查看本域是否合法;
若本域合法,則發(fā)送跨域請(qǐng)求;若不合法,則直接封殺請(qǐng)求。
此處注意,如果本域非法,F(xiàn)lash就會(huì)直接封殺了請(qǐng)求,那么我們?cè)跒g覽器控制臺(tái)是捕獲不到該請(qǐng)求的,因?yàn)榫蜎](méi)發(fā)出去。
那么Flash是怎么判斷本域是否合法的呢?我們先來(lái)看一下一個(gè)最簡(jiǎn)單的corssdomain.xml文件結(jié)構(gòu)。
所有的 crossdomain.xml 都以
其中,鍵值 domain 表示允許跨域的源,此處就跟 CORS 的 Access-Control-Allow-Origin 字段一樣了。
而 secure ,則表示請(qǐng)求是否以加密進(jìn)行傳輸。如果 corssdomain.xml 文件是從 https 協(xié)議下加載的,那么 secure 默認(rèn)為 true。此時(shí)Flash若發(fā)現(xiàn)本域?yàn)榉?https 協(xié)議,縱使 domain 合法,也會(huì)封殺請(qǐng)求。如果secure為false,則表明Flash可以發(fā)送非https加密過(guò)的請(qǐng)求。
Security.allowDomain 跨域權(quán)限授予如果說(shuō)介紹 crossdomain.xml 文件時(shí)我們是以 Client 端為角度的,那么介紹 Security.allowDomain 則必須以 Server 作為角度。
你可能會(huì)遇到如下情形,開(kāi)發(fā)了多個(gè)swf,它們之間相互依賴(lài),但以不同的域發(fā)布到網(wǎng)上。此時(shí)你只希望某些特定的域才有權(quán)限去修改或調(diào)用該swf中的屬性及方法。那么此時(shí),你就需要用到allowDomain方法對(duì)你所允許的域進(jìn)行授權(quán)了。
以下是 allowDomain 的描述:
允許指定的域中的 SWF 文件訪問(wèn)調(diào)用了此方法的 SWF 文件中的對(duì)象和變量。
再舉個(gè)栗子,http://a.com/a.swf 需要調(diào)用及修改 http://b.com/b.swf 中的屬性及方法。
那么,就必須在b.swf中調(diào)用 Security.allowDomain("a.com")以允許a.com域?qū)ψ约哼M(jìn)行訪問(wèn)。
另外,要注意非常重要的一點(diǎn),Security.allowDomain跨域權(quán)限授予是不對(duì)稱(chēng)的。
也就是說(shuō),在上面的栗子中,只允許a.swf訪問(wèn)b.swf,但b.swf卻不能夠訪問(wèn)a.swf。
如果非要這樣做,那么就在a.swf中對(duì)b.com進(jìn)行權(quán)限授予。
其次,對(duì)于HTTPS來(lái)說(shuō),即使調(diào)用了該方法,若試圖利用在HTTP下的swf去修改HTTPS下的swf,此時(shí)也是非法的。因?yàn)檫@本身就不安全。
如果非要這樣做,可以讓HTTPS下的swf調(diào)用Security.allowInsecureDomain()對(duì)HTTP域進(jìn)行權(quán)限授予
跨域方式對(duì)比反觀 Flash 跨域與H5 CORS 跨域,雖然兩者在形式上有所不同,但本質(zhì)上都向著以下兩個(gè)特點(diǎn)靠攏:
先詢(xún)問(wèn),后請(qǐng)求; 安全性靠Server端來(lái)維護(hù)。
對(duì)于 CORS 簡(jiǎn)單請(qǐng)求來(lái)說(shuō),瀏覽器是不會(huì)進(jìn)行預(yù)檢請(qǐng)求發(fā)送的,這樣一個(gè)請(qǐng)求搞定所有的事,卻不一定完全合理。因?yàn)閷?duì)于瀏覽器來(lái)說(shuō),我在沒(méi)有知道Server是否認(rèn)為我的請(qǐng)求合法前,就已經(jīng)拋出了大量的查詢(xún)數(shù)據(jù)。這就有可能造成數(shù)據(jù)傳輸?shù)娜哂唷?/p>
另外,如果由于開(kāi)發(fā)過(guò)程不當(dāng),頻繁發(fā)送不合法的跨域請(qǐng)求,本身就是一個(gè)資源的浪費(fèi)。
所以,才需要到復(fù)雜請(qǐng)求。
而對(duì)于 Flash crossdomain.xml 這種方式(與 CORS 復(fù)雜請(qǐng)求類(lèi)似),就避免了頻繁發(fā)送不合法的跨域請(qǐng)求,因?yàn)樵赾rossdomain.xml返回之前,F(xiàn)lash是不會(huì)發(fā)送任何跨域請(qǐng)求,直接在本地就將其封殺。同時(shí)crossdomain.xml并非每次跨域前都會(huì)請(qǐng)求,其有一個(gè)有效期。
但若我本身只需請(qǐng)求一次數(shù)據(jù),但Server由于業(yè)務(wù)繁重卻給我返回一個(gè)龐大的crossdomain.xml,這反而又顯得不合理了。
文章來(lái)源:http://mp.weixin.qq.com/s/_KA...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/82857.html
摘要:上節(jié)我們講了同源策略,這節(jié)我們講講如何跨域。當(dāng)這些從的腳本執(zhí)行出錯(cuò),因?yàn)檫`背了同源策略為了保證用戶(hù)信息不被泄露,錯(cuò)誤信息不會(huì)顯示出來(lái),取而代之只會(huì)返回一個(gè)。 前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門(mén)技術(shù)就算入門(mén),但也僅僅是入門(mén),現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/CSS/JS),本著提升技術(shù)水平,打牢基礎(chǔ)知識(shí)的中心思想,我們開(kāi)課啦(每...
摘要:用于告知瀏覽器可以將預(yù)先檢查請(qǐng)求返回結(jié)果緩存的時(shí)間,在緩存有效期內(nèi),瀏覽器會(huì)使用緩存的預(yù)先檢查結(jié)果判斷是否發(fā)送跨域請(qǐng)求。 跨域,老生常談的問(wèn)題 簡(jiǎn)述 作為一只前端菜鳥(niǎo),跨域方面只懂得JSONP和CORS,并未曾深入了解。但隨著春招越來(lái)越近,就算是菜鳥(niǎo)也要猛振翅膀。近幾日仔細(xì)研究了跨域問(wèn)題,寫(xiě)下這篇文章,希望對(duì)開(kāi)發(fā)者們有所幫助。在讀本文前,希望您對(duì)以下知識(shí)略有了解。 瀏覽器同源策略 n...
摘要:需注意的是由于同源策略的限制,所讀取的為跨域請(qǐng)求接口所在域的,而非當(dāng)前頁(yè)。目前,所有瀏覽器都支持該功能需要使用對(duì)象來(lái)支持,也已經(jīng)成為主流的跨域解決方案。反向代理接口跨域跨域原理同源策略是瀏覽器的安全策略,不是協(xié)議的一部分。 什么是跨域? 跨域是指一個(gè)域下的文檔或腳本試圖去請(qǐng)求另一個(gè)域下的資源,這里跨域是廣義的。 廣義的跨域: 1.) 資源跳轉(zhuǎn): A鏈接、重定向、表單提交 2.) 資源...
摘要:瀏覽器同源策略我們?yōu)楹我芯靠缬騿?wèn)題因?yàn)闉g覽器的同源策略規(guī)定某域下的客戶(hù)端在沒(méi)明確授權(quán)的情況下,不能讀寫(xiě)另一個(gè)域的資源。 跨域,老生常談的問(wèn)題 簡(jiǎn)述 作為一只前端菜鳥(niǎo),跨域方面只懂得JSONP和CORS,并未曾深入了解。但隨著春招越來(lái)越近,就算是菜鳥(niǎo)也要猛振翅膀。近幾日仔細(xì)研究了跨域問(wèn)題,寫(xiě)下這篇文章,希望對(duì)開(kāi)發(fā)者們有所幫助。在讀本文前,希望您對(duì)以下知識(shí)略有了解。 瀏覽器同源策略 n...
摘要:在接觸前端開(kāi)發(fā)起,跨域這個(gè)詞就一直以很高的頻率在我們學(xué)習(xí)工作中重復(fù)出現(xiàn),最近在工作中遇到了跨域的相關(guān)問(wèn)題,這里我把它總結(jié)記錄一下。 在接觸前端開(kāi)發(fā)起,跨域這個(gè)詞就一直以很高的頻率在我們學(xué)習(xí)工作中重復(fù)出現(xiàn),最近在工作中遇到了跨域的相關(guān)問(wèn)題,這里我把它總結(jié)記錄一下。關(guān)于跨域,有N種類(lèi)型,現(xiàn)在我只專(zhuān)注于ajax請(qǐng)求跨域(ajax跨域只是屬于瀏覽器同源策略中的一部分,其它的這里不做介紹),內(nèi)容...
閱讀 3655·2021-11-12 10:36
閱讀 3053·2021-09-22 15:35
閱讀 2991·2021-09-04 16:41
閱讀 1331·2019-08-30 15:55
閱讀 3730·2019-08-29 18:43
閱讀 2223·2019-08-23 18:24
閱讀 1561·2019-08-23 18:10
閱讀 2058·2019-08-23 11:31