前端跨域解決方案匯總-前端開(kāi)發(fā)博客
《前端跨域解決方案匯總-前端開(kāi)發(fā)博客》由會(huì)員分享,可在線(xiàn)閱讀,更多相關(guān)《前端跨域解決方案匯總-前端開(kāi)發(fā)博客(9頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
1、前端跨域解決方案匯總-前端開(kāi)發(fā)博客 2017-06-20 編者注:關(guān)于跨域的文章,之前分享過(guò)很多,來(lái)看看這篇前端跨域解決方案,由簡(jiǎn)及深介紹各種存在的跨域請(qǐng)求解決方案,包括 document.domain, location.hash, window.name, window.postMessage, JSONP, WebSocket, CORS。原文:hijiangtao.github.io同源策略限制從一個(gè)源加載的文檔或腳本如何與來(lái)自另一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離潛在惡意文件的關(guān)鍵的安全機(jī)制。但是有時(shí)候跨域請(qǐng)求資源是合理的需求,本文嘗試從多篇文章中匯總至今存在的所有跨域請(qǐng)求解
2、決方案??缬蛘?qǐng)求首先需要了解的是同源和跨源的概念。對(duì)于相同源,其定義為:如果協(xié)議、端口(如果指定了一個(gè))和主機(jī)對(duì)于兩個(gè)頁(yè)面是相同的,則兩個(gè)頁(yè)面具有相同的源。只要三者之一任意一點(diǎn)有不同,那么就為不同源。當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器的域或端口不同的域或不同的端口請(qǐng)求一個(gè)資源時(shí),資源會(huì)發(fā)起一個(gè)跨域 HTTP 請(qǐng)求。而有關(guān)跨域請(qǐng)求受到限制的原因可以參考如下 MDN 文檔片段:跨域不一定是瀏覽器限制了發(fā)起跨站請(qǐng)求,而也可能是跨站請(qǐng)求可以正常發(fā)起,但是返回結(jié)果被瀏覽器攔截了。最好的例子是 CSRF 跨站攻擊原理,請(qǐng)求是發(fā)送到了后端服務(wù)器無(wú)論是否跨域!注意:有些瀏覽器不允許從 HTTPS 的域跨域訪(fǎng)
3、問(wèn) HTTP,比如 Chrome 和 Firefox,這些瀏覽器在請(qǐng)求還未發(fā)出的時(shí)候就會(huì)攔截請(qǐng)求,這是一個(gè)特例。解決方法匯總以下我們由簡(jiǎn)及深介紹各種存在的跨域請(qǐng)求解決方案,包括 document.domain, location.hash, window.name, window.postMessage, JSONP, WebSocket, CORS。document.domaindocument.domain 的作用是用來(lái)獲取/設(shè)置當(dāng)前文檔的原始域部分,例如:// 對(duì)于文檔 www.example.xxx/good.htmldocument.domain="www.example.xxx"/
4、/ 對(duì)于URI http://developer.mozilla.org/en/docs/DOM document.domain="developer.mozilla.org"如果當(dāng)前文檔的域無(wú)法識(shí)別,那么 domain 屬性會(huì)返回 null。在根域范圍內(nèi),Mozilla允許你把domain屬性的值設(shè)置為它的上一級(jí)域。例如,在 developer.mozilla.org 域內(nèi),可以把domain設(shè)置為 "mozilla.org" 但不能設(shè)置為 "" 或者"org"。因此,若兩個(gè)源所用協(xié)議、端口一致,主域相同而二級(jí)域名不同的話(huà),可以借鑒該方法解決跨域請(qǐng)求。比如若我們?cè)?http://a.gith
5、ub.io 頁(yè)面執(zhí)行以下語(yǔ)句:document.domain = "github.io"那么之后頁(yè)面對(duì) github.io 發(fā)起請(qǐng)求時(shí)頁(yè)面則會(huì)成功通過(guò)對(duì) github.io 的同源檢測(cè)。比較直接的一個(gè)操作是,當(dāng)我們?cè)赼.github.io 頁(yè)面中利用 iframe 去加載 github.io 時(shí),通過(guò)如上的賦值后,我們可以在 a.github.io 頁(yè)面中去操作 iframe 里的內(nèi)容。我們同時(shí)考慮另一種情況:存在兩個(gè)子域名 a.github.io 以及 b.github.io, 其中前者域名下網(wǎng)頁(yè) a.html 通過(guò) iframe 引入了后者域名下的 b.html,此時(shí)在 a.html 中是
6、無(wú)法直接操作 b.html 的內(nèi)容的。同樣利用 document.domain,我們?cè)趦蓚€(gè)頁(yè)面中均加入document.domain=github.io這樣在以上的 a.html 中就可以操作通過(guò) iframe 引入的 b.html 了。document.domain 的優(yōu)點(diǎn)在于解決了主語(yǔ)相同的跨域請(qǐng)求,但是其缺點(diǎn)也是很明顯的:比如一個(gè)站點(diǎn)受到攻擊后,另一個(gè)站點(diǎn)會(huì)因此引起安全漏洞;若一個(gè)頁(yè)面中引入多個(gè) iframe,想要操作所有的 iframe 則需要設(shè)置相同的 domain。location.hashlocation.hash 是一個(gè)可讀可寫(xiě)的字符串,該字符串是 URL 的錨部分(從 # 號(hào)
7、開(kāi)始的部分)。例如:// 對(duì)于頁(yè)面 :1234/test.htm#part2location.hash = "#part2"同時(shí),由于我們知道改變 hash 并不會(huì)導(dǎo)致頁(yè)面刷新,所以可以利用 hash 在不同源間傳遞數(shù)據(jù)。假設(shè) github.io 域名下 a.html 和 shaonian.eu 域名下 b.html 存在跨域請(qǐng)求,那么利用 location.hash 的一個(gè)解決方案如下:a.html 頁(yè)面中創(chuàng)建一個(gè)隱藏的 iframe, src 指向 b.html,其中 src 中可以通過(guò) hash 傳入?yún)?shù)給 b.htmlb.html 頁(yè)面在處理完傳入的 hash 后通過(guò)修改 a.html
8、 的 hash 值達(dá)到將數(shù)據(jù)傳送給 a.html 的目的a.html 頁(yè)面添加一個(gè)定時(shí)器,每隔一定時(shí)間判斷自身的 location.hash 是否變化,以此響應(yīng)處理以上步驟中需要注意第二點(diǎn):如何在 iframe 頁(yè)面中修改 父親頁(yè)面的 hash 值。由于在 IE 和 Chrome 下,兩個(gè)不同域的頁(yè)面是不允許 parent.location.hash 這樣賦值的,所以對(duì)于這種情況,我們需要在父親頁(yè)面域名下添加另一個(gè)頁(yè)面來(lái)實(shí)現(xiàn)跨域請(qǐng)求,具體如下:假設(shè) a.html 中 iframe 引入了 b.html, 數(shù)據(jù)需要在這兩個(gè)頁(yè)面之間傳遞,且 c.html 是一個(gè)與 a.html 同源的頁(yè)面a.ht
9、ml 通過(guò) iframe 將數(shù)據(jù)通過(guò) hash 傳給 b.htmlb.html 通過(guò) iframe 將數(shù)據(jù)通過(guò) hash 傳給 c.htmlc.html 通過(guò) parent.parent.location.hash 設(shè)置 a.html 的 hash 達(dá)到傳遞數(shù)據(jù)的目的location.bash 方法的優(yōu)點(diǎn)在于可以解決域名完全不同的跨域請(qǐng)求,并且可以實(shí)現(xiàn)雙向通訊;而缺點(diǎn)則包括以下幾點(diǎn):利用這種方法傳遞的數(shù)據(jù)量受到 url 大小的限制,傳遞數(shù)據(jù)類(lèi)型有限由于數(shù)據(jù)直接暴露在 url 中則存在安全問(wèn)題若瀏覽器不支持 onhashchange 事件,則需要通過(guò)輪訓(xùn)來(lái)獲知 url 的變化有些瀏覽器會(huì)在 ha
10、sh 變化時(shí)產(chǎn)生歷史記錄,因此可能影響用戶(hù)體驗(yàn)window.name該屬性用于獲取/設(shè)置窗口的名稱(chēng)。其特征在于:一個(gè)窗口的生命周期內(nèi),窗口載入的所有頁(yè)面共享該值,且都具有對(duì)該屬性的讀寫(xiě)權(quán)限。這意味著如果不修改該值,那么在不同頁(yè)面加載之后該值也不會(huì)變,且其支持長(zhǎng)達(dá) 2MB 的存儲(chǔ)量。利用該特性我們可以將跨域請(qǐng)求用如下步驟解決:在 a.github.io/a.html 中創(chuàng)建 iframe 指向 b.github.io/b.html (頁(yè)面會(huì)將自身的 window.name 附在 iframe 上)給 a.github.io/a.html 添加監(jiān)聽(tīng) iframe 的 onload 事件,在該事件中
11、將 iframe 的 src 設(shè)置為本地域的代理文件(代理文件和a.html處于同一域下,可以相互通信),同時(shí)可以傳出 iframe 的 name 值獲取數(shù)據(jù)后銷(xiāo)毀 iframe,釋放內(nèi)存,同時(shí)也保證了安全window.name 的優(yōu)勢(shì)在于巧妙地繞過(guò)了瀏覽器的跨域訪(fǎng)問(wèn)限制,但同時(shí)它又是安全操作。window.postMessageHTML5 為了解決這個(gè)問(wèn)題,引入了一個(gè)全新的 API:跨文檔通信 API(Cross-document messaging)。這個(gè) API 為 window 對(duì)象新增了一個(gè) window.postMessage 方法,允許跨窗口通信,不論這兩個(gè)窗口是否同源。API
12、的詳細(xì)使用方法請(qǐng)見(jiàn) MDN。JSONPJSONP, 全稱(chēng) JSON with Padding,是使用 AJAX 實(shí)現(xiàn)的請(qǐng)求不同源的跨域。其基本原理:網(wǎng)頁(yè)通過(guò)添加一個(gè) // test.js// 調(diào)用callback函數(shù),并以json數(shù)據(jù)形式作為闡述傳遞,完成回調(diào)callback({message:"success"}); 為了保證 script 的靈活,我們可以通過(guò) JavaScript 動(dòng)態(tài)創(chuàng)建 script 標(biāo)簽,并通過(guò) HTTP 參數(shù)向服務(wù)器傳入回調(diào)函數(shù)名,案例如下所示:jQuery 有相應(yīng)的 JSONP 的實(shí)現(xiàn)方法,見(jiàn) API。JSONP的優(yōu)點(diǎn)在于簡(jiǎn)單適用,老式瀏覽器全部支持,服務(wù)器改造
13、小。不需要XMLHttpRequest或ActiveX的支持;但缺點(diǎn)是只支持 GET 請(qǐng)求。WebSocketWebSocket 協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。CORSCORS是一個(gè)W3C標(biāo)準(zhǔn),全稱(chēng)是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制??缬蛸Y源共享( CORS )機(jī)制允許 Web 應(yīng)用服務(wù)器進(jìn)行跨域訪(fǎng)問(wèn)控制,從而使跨域數(shù)據(jù)傳輸?shù)靡园踩M(jìn)行。其需要服務(wù)端和客戶(hù)端同時(shí)支持??缬蛸Y源共享標(biāo)準(zhǔn)( cross-origin sh
14、aring standard )允許在下列場(chǎng)景中使用跨域 HTTP 請(qǐng)求:由 XMLHttpRequest 或 Fetch 發(fā)起的跨域 HTTP 請(qǐng)求Web 字體 (CSS 中通過(guò) @font-face 使用跨域字體資源), 因此,網(wǎng)站就可以發(fā)布 TrueType 字體資源,并只允許已授權(quán)網(wǎng)站進(jìn)行跨站調(diào)用WebGL 貼圖使用 drawImage 將 Images/video 畫(huà)面繪制到 canvas樣式表(使用 CSSOM)Scripts (未處理的異常)CORS 存在以下三種主要場(chǎng)景,分別是簡(jiǎn)單請(qǐng)求,預(yù)檢請(qǐng)求和附帶身份憑證的請(qǐng)求。簡(jiǎn)單請(qǐng)求:若只使用 GET, HEAD 或者 POST 請(qǐng)求,
15、且除 CORS 安全的首部字段集合外,無(wú)人為設(shè)置該集合之外的其他首部字段,同時(shí) Content-Type 值屬于下列之一,那么該請(qǐng)求則可以被視為簡(jiǎn)單請(qǐng)求:application/x-www-form-urlencodedmultipart/form-datatext/plain此情況下,若服務(wù)端返回的 Access-Control-Allow-Origin: * ,則表明該資源可以被任意外域訪(fǎng)問(wèn)。若要指定僅允許來(lái)自某些域的訪(fǎng)問(wèn),需要將 * 設(shè)定為該域,例如:Access-Control-Allow-Origin: http://foo.example預(yù)檢請(qǐng)求:與前述簡(jiǎn)單請(qǐng)求不同,該要求必須首先
16、使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求到服務(wù)器,以獲知服務(wù)器是否允許該實(shí)際請(qǐng)求。當(dāng)請(qǐng)求滿(mǎn)足以下三個(gè)條件任意之一時(shí), 即應(yīng)首先發(fā)送預(yù)檢請(qǐng)求:使用了 PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH 中任一的 HTTP 方法人為設(shè)置了對(duì) CORS 安全的首部字段集合之外的其他首部字段Content-Type 的值不屬于下列之一application/x-www-form-urlencodedmultipart/form-datatext/plain預(yù)檢請(qǐng)求完成之后(通過(guò) OPTIONS 方法實(shí)現(xiàn)),才發(fā)送實(shí)際請(qǐng)求。一個(gè)示范 HTTP 請(qǐng)求如下所示:var
17、invocation = new XMLHttpRequest();var url = http://bar.other/resources/post-here/;var body = Arun; function callOtherDomain(){ if(invocation) { invocation.open(POST, url, true); invocation.setRequestHeader(X-PINGOTHER, pingpong); invocation.setRequestHeader(Content-Type, applic
18、ation/xml); invocation.onreadystatechange = handler; invocation.send(body); }}附帶身份憑證的請(qǐng)求:這種方式的特點(diǎn)在于能夠在跨域請(qǐng)求時(shí)向服務(wù)器發(fā)送憑證請(qǐng)求,例如 Cookies (withCredentials 標(biāo)志設(shè)置為 true)。一般而言,對(duì)于跨域 XMLHttpRequest 或 Fetch 請(qǐng)求,瀏覽器不會(huì)發(fā)送身份憑證信息。如果要發(fā)送憑證信息,需要設(shè)置 XMLHttpRequest 的某個(gè)特殊標(biāo)志位。但是需要注意的是,如果服務(wù)器端的響應(yīng)中未攜帶 Access-Control-All
19、ow-Credentials: true,瀏覽器將不會(huì)把響應(yīng)內(nèi)容返回給請(qǐng)求的發(fā)送者。附帶身份憑證的請(qǐng)求與通配符對(duì)于附帶身份憑證的請(qǐng)求,服務(wù)器不得設(shè)置 Access-Control-Allow-Origin 的值為“*”。這是因?yàn)檎?qǐng)求的首部中攜帶了 Cookie 信息,如果 Access-Control-Allow-Origin 的值為“*”,請(qǐng)求將會(huì)失敗。而將 Access-Control-Allow-Origin 的值設(shè)置為 http://foo.example,則請(qǐng)求將成功執(zhí)行。另外,響應(yīng)首部中也攜帶了 Set-Cookie 字段,嘗試對(duì) Cookie 進(jìn)行修改。如果操作失敗,將會(huì)拋出異常
20、。MDN 引例如下:var invocation = new XMLHttpRequest();var url = http://bar.other/resources/credentialed-content/; function callOtherDomain(){ if(invocation) { invocation.open(GET, url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); }}其實(shí)由上我們知道,CORS 的優(yōu)點(diǎn)也非常明顯:CORS支持所有類(lèi)型的HTTP請(qǐng)求,是跨域HTTP請(qǐng)求的根本解決方案。以上就是所有的跨域請(qǐng)求解決方案,根據(jù)實(shí)際生產(chǎn)環(huán)境,總有一款適合你。參考
- 溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025《增值稅法》高質(zhì)量發(fā)展的增值稅制度規(guī)范增值稅的征收和繳納
- 深入學(xué)習(xí)《中華人民共和國(guó)科學(xué)技術(shù)普及法》推進(jìn)實(shí)現(xiàn)高水平科技自立自強(qiáng)推動(dòng)經(jīng)濟(jì)發(fā)展和社會(huì)進(jìn)步
- 激揚(yáng)正氣淬煉本色踐行使命廉潔從政黨課
- 加強(qiáng)廉潔文化建設(shè)夯實(shí)廉政思想根基培育風(fēng)清氣正的政治生態(tài)
- 深入學(xué)習(xí)2024《突發(fā)事件應(yīng)對(duì)法》全文提高突發(fā)事件預(yù)防和應(yīng)對(duì)能力規(guī)范突發(fā)事件應(yīng)對(duì)活動(dòng)保護(hù)人民生命財(cái)產(chǎn)安全
- 2023年四年級(jí)數(shù)學(xué)上冊(cè)第一輪單元滾動(dòng)復(fù)習(xí)第10天平行四邊形和梯形作業(yè)課件新人教版
- 2023年四年級(jí)數(shù)學(xué)上冊(cè)第14單元階段性綜合復(fù)習(xí)作業(yè)課件新人教版
- 2023年四年級(jí)數(shù)學(xué)上冊(cè)易錯(cuò)清單十五課件新人教版
- 2023年四年級(jí)數(shù)學(xué)上冊(cè)易錯(cuò)清單七課件西師大版
- 2023年五年級(jí)數(shù)學(xué)下冊(cè)易錯(cuò)清單六作業(yè)課件北師大版
- 2023年五年級(jí)數(shù)學(xué)下冊(cè)易錯(cuò)清單二作業(yè)課件北師大版
- 2023年五年級(jí)數(shù)學(xué)下冊(cè)四分?jǐn)?shù)的意義和性質(zhì)第10課時(shí)異分母分?jǐn)?shù)的大小比較作業(yè)課件蘇教版
- 2023年五年級(jí)數(shù)學(xué)下冊(cè)周周練四作業(yè)課件北師大版
- 2023年五年級(jí)數(shù)學(xué)下冊(cè)六折線(xiàn)統(tǒng)計(jì)圖單元復(fù)習(xí)卡作業(yè)課件西師大版
- 2023年四年級(jí)數(shù)學(xué)上冊(cè)6除數(shù)是兩位數(shù)的除法單元易錯(cuò)集錦一作業(yè)課件新人教版