摘要:開發(fā)者需要在中設(shè)置屬性為跨域是的簡(jiǎn)稱這是一種利用瀏覽器漏洞解決跨域的辦法腳本元素可以不受瀏覽器同源策略的限制。
什么是瀏覽器同源策略?
同源是指,域名,協(xié)議,端口號(hào)均相同,如圖:
注意:localhost和127.0.0.1雖然都指向本機(jī),但也是跨域.
瀏覽器同源策略(same-origin policy).簡(jiǎn)單的講,同源策略就是瀏覽器為了保證用戶安全,防止惡意的網(wǎng)站盜取數(shù)據(jù),禁止不同域之間的JS進(jìn)行交互.會(huì)限制如下行為:
Cookie,LocalStorage 和indexDB無法讀取.
DOM無法獲取.
AJAX請(qǐng)求不能發(fā)送.
解決跨域的方法有如下幾種 CORS資源共享CORS是跨域資源共享(Crocss-Origin Resource Sharing)的縮寫.是W3C標(biāo)準(zhǔn).跨域資源共享機(jī)制允許Web應(yīng)用服務(wù)器進(jìn)行跨域訪問控制,從而使跨域傳輸?shù)靡园踩M(jìn)行.對(duì)于這個(gè)方式阮一峰老師有一篇文章專門講這個(gè)的,跨域資源共享CORS詳解可供參考.還有就是MDN里有關(guān)于HTTP訪問控制的文檔.HTTP訪問控制CORS
簡(jiǎn)單的說就是:
請(qǐng)求方在頭信息中多一個(gè)Origin字段來說明本次請(qǐng)求來自哪個(gè)源.(協(xié)議+域名+端口)
服務(wù)器響應(yīng)頭信息中會(huì)多幾個(gè)字段
Access-Control-Allow-Origin
該字段是必須的。它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求.
Access-Control-Allow-Credentials
該字段可選。它的值是一個(gè)布爾值,表示是否允許發(fā)送Cookie。默認(rèn)情況下,Cookie不包括在CORS請(qǐng)求之中。設(shè)為true,即表示服務(wù)器明確許可,Cookie可以包含在請(qǐng)求中,一起發(fā)給服務(wù)器。這個(gè)值也只能設(shè)為true,如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可.
Access-Control-Expose-Headers
該字段可選。CORS請(qǐng)求時(shí),XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader("FooBar")可以返回FooBar字段的值。
開發(fā)者需要在AJAX中設(shè)置withCredentials屬性為true.JSONP跨域
JSONP是JSON with Padding的簡(jiǎn)稱.這是一種利用瀏覽器漏洞解決跨域的辦法.HTML腳本元素可以不受瀏覽器同源策略的限制。即我們請(qǐng)求HTML、CSS、JS文件時(shí)瀏覽器不會(huì)做限制。所以運(yùn)用這個(gè)特點(diǎn),通過加載外部js文件的方式來向其他資源發(fā)出http請(qǐng)求。正是因?yàn)槭钦?qǐng)求文件,所以JOSNP只能GET,不能POST.簡(jiǎn)單來說,JSONP方案就是頁面動(dòng)態(tài)創(chuàng)建一個(gè)script標(biāo)簽.
然后服務(wù)端根據(jù)我們傳過去的參數(shù),進(jìn)行處理.
舉個(gè)例子:
callBackFunc = function(data){ console.log(data); }; var script = document.createElenent("script"); script.type = "text/javascript"; script.src = "http://www.localhost:8888/data.json?callBack= callBackFunc"; document.body.appendChild(script);
JSONP的缺點(diǎn):
只能進(jìn)行GET請(qǐng)求,無法發(fā)送POST請(qǐng)求.
缺乏錯(cuò)誤異常處理機(jī)制,如果沒有調(diào)用成功,也沒有任何提示.例如404無法檢測(cè)具體錯(cuò)誤原因.
嚴(yán)重安全漏洞,借助JSONP可進(jìn)行跨站偽造攻擊(CSRF).
服務(wù)器代理瀏覽器有跨域限制,但是服務(wù)器沒有,所以可以由服務(wù)器請(qǐng)求所要域的資源再返回給客戶端。
服務(wù)器可解決一切跨域問題.window.postMessage方案
window.postMessage() 方法可以安全地實(shí)現(xiàn)跨源通信。通常,對(duì)于兩個(gè)不同頁面的腳本,只有當(dāng)執(zhí)行它們的頁面位于具有相同的協(xié)議(通常為https),端口號(hào)(443為https的默認(rèn)值),以及主機(jī) (兩個(gè)頁面的模數(shù) Document.domain設(shè)置為相同的值) 時(shí),這兩個(gè)腳本才能相互通信。window.postMessage() 方法提供了一種受控機(jī)制來規(guī)避此限制,只要正確的使用,這種方法就很安全。
window.postMessage() 方法被調(diào)用時(shí),會(huì)在所有頁面腳本執(zhí)行完畢之后(e.g., 在該方法之后設(shè)置的事件、之前設(shè)置的timeout 事件,etc.)向目標(biāo)窗口派發(fā)一個(gè) MessageEvent 消息。 該MessageEvent消息有四個(gè)屬性需要注意: message 屬性表示該message 的類型; data 屬性為 window.postMessage 的第一個(gè)參數(shù);origin 屬性表示調(diào)用window.postMessage() 方法時(shí)調(diào)用頁面的當(dāng)前狀態(tài); source 屬性記錄調(diào)用 window.postMessage() 方法的窗口信息。
關(guān)于這個(gè)的文章可參考window.postMessage
舉個(gè)例子:
頁面和其他打開的新窗口的數(shù)據(jù)傳遞
//同域 - a頁面 跳轉(zhuǎn) //b頁面
頁面與嵌套的iframe消息
//a頁面 var iframe = document.getElementsByTagName("iframe")[0]; window.onMessage = function(event) { if(event.source == iframe.contentWindow) {} //嵌套iframe除了origin外還可以比較用source } //iframe頁面 window.parent.postMessage(data, target) window.addEventListener("message",function(e){ if(e.source!=window.parent) return; //子頁面可以通過此方法判斷是否是父頁面的消息 window.parent.postMessage("data","*"); },false);
多窗口之間消息傳遞不是指我用瀏覽器分別打開了兩個(gè)頁面,就能互相通信了。需要一個(gè)otherWindow,一個(gè)其他窗口的引用 window.postMessage
語法 ——> otherWindow.postMessage(message, targetOrigin, [transfer]); otherWindow ——> 其他窗口的一個(gè)引用,比如iframe的contentWindow屬性、執(zhí)行window.open返回的窗口對(duì)象、或者是命名過或數(shù)值索引的window.frames。 message ——> 將要發(fā)送到其他 window的數(shù)據(jù) targetOrigin——> 通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個(gè)URI。iframe解決跨域
iframe跨域也是利用瀏覽器中帶有src的標(biāo)簽可以跨域訪問.凡是擁有src屬性的標(biāo)簽都有跨域的能力.例如:
子窗口(http://script.a.com/b.html)
這樣就能在子窗口獲取父窗口里的數(shù)據(jù)了.
1、安全性,當(dāng)一個(gè)站點(diǎn)(b.a.com)被攻擊后,另一個(gè)站點(diǎn)(c.a.com)會(huì)引起安全漏洞。2) location.hash + iframe
2、如果一個(gè)頁面中引入多個(gè)iframe,要想能夠操作所有iframe,必須都得設(shè)置相同domain。
對(duì)于主域不同的情形,可用location.hash 和window.name解決.
原理是利用location.hash來進(jìn)行傳值。在url: http://a.com#segmentfault中的‘#segmentfault’就是location.hash,改變hash并不會(huì)導(dǎo)致頁面刷新,所以可以利用hash值來進(jìn)行數(shù)據(jù)傳遞,當(dāng)然數(shù)據(jù)容量是有限的。假設(shè)域名a.com下的文件test1.html要和b.com域名下的test2.html傳遞信息,test1.html首先創(chuàng)建自動(dòng)創(chuàng)建一個(gè)隱藏的iframe,iframe的src指向b.com域名下的test2.html頁面,這時(shí)的hash值可以做參數(shù)傳遞用。test2.html響應(yīng)請(qǐng)求后再將通過修改test1.html的hash值來傳遞數(shù)據(jù)(由于兩個(gè)頁面不在同一個(gè)域下IE、Chrome不允許修改parent.location.hash的值,所以要借助于a.com域名下的一個(gè)代理iframe;Firefox可以修改)。同時(shí)在test1.html上加一個(gè)定時(shí)器,隔一段時(shí)間來判斷l(xiāng)ocation.hash的值有沒有變化,一點(diǎn)有變化則獲取獲取hash值。
a.com下的test1.html
function startRequest(){ var iframe = document.createElement("iframe"); iframe.style.display = "none"; iframe.src = "http://www.b.com/test2.html#paramdo"; document.body.appendChild(iframe); } function checkHash() { try { var data = location.hash ? location.hash.substring(1) : ""; if (console.log) { console.log("Now the data is "+data); } } catch(e) {}; } setInterval(checkHash, 2000);
b.com域名下的test2.html
//模擬一個(gè)簡(jiǎn)單的參數(shù)處理操作 switch(location.hash){ case "#paramdo": callBack(); break; case "#paramset": //do something…… break; } function callBack(){ try { parent.location.hash = "somedata"; } catch (e) { // ie、chrome的安全機(jī)制無法修改parent.location.hash, // 所以要利用一個(gè)中間的b.com域下的代理iframe var iframeproxy = document.createElement("iframe"); iframeproxy.style.display = "none"; iframeproxy.src = "http://a.com/test3.html#somedata"; // 注意該文件在"a.com"域下 document.body.appendChild(iframeproxy); } }
a.com域名下的test3.html
//因?yàn)閜arent.parent和自身屬于同一個(gè)域,所以可以改變其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);
缺點(diǎn),暴露數(shù)據(jù)在url中.3) window.name + iframe
對(duì)于主域不同的情形,可用location.hash 和window.name解決.
iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個(gè)就巧妙地繞過了瀏覽器的跨域訪問限制,但同時(shí)它又是安全操作。
有三個(gè)頁面:
a.com/test1.html :應(yīng)用頁面
a.com/proxy.html :代理頁面,需要和應(yīng)用頁面在同一域下.
b.com/test2.html : 存放應(yīng)用頁面需要用到數(shù)據(jù)的頁面(數(shù)據(jù)頁面)
1) 應(yīng)用頁面創(chuàng)建一個(gè)iframe,src指向數(shù)據(jù)頁面.數(shù)據(jù)頁面會(huì)把數(shù)據(jù)附加到這個(gè)iframe的window.name上.
b.com/test2.html 代碼
2) 在應(yīng)用頁面中監(jiān)聽iframe的onload事件,在事件中設(shè)置這個(gè)iframe的src指向本地域的代理文件(代理頁面和應(yīng)用頁面在同一域下,可以相互通信.)
a.com/test1.html 代碼
3) 獲取數(shù)據(jù)以后銷毀這個(gè)iframe,釋放內(nèi)存.這也保證了安全性.(不被其他域iframe 訪問)
window.top方案window.top方法可以訪問最頂層的window對(duì)象,可以取到最頂層window對(duì)象的屬性和方法。這樣子框架就可以操作父頁面的交互了。window.parent可以得到父框架的window對(duì)象。
1) a頁面代碼
2) b頁面的代碼
3) c頁面代碼
cookie 和 WebSocket 協(xié)議跨域cookie除了有exprise這個(gè)屬性之后還有path這個(gè)屬性,這個(gè)屬性是用來設(shè)置可訪問到cookie的路徑的,默認(rèn)的是在當(dāng)前cookie頁面的子目錄下是可以訪問到的,但是默認(rèn)的情況下我們是無法再其他父目錄下面訪問到這個(gè)cookie,這個(gè)時(shí)候我們就可以通過設(shè)置cookie來實(shí)現(xiàn)這個(gè)功能
如上面所說,但是在跨域之間的傳值要怎樣實(shí)現(xiàn)呢,其實(shí)cookie除了有path,還存在domain,domain這個(gè)屬性是可以實(shí)現(xiàn)跨域的,但是必須保證這兩個(gè)域名有公共部分,何為公共部分?就是像www.qq.com和www.sport.qq.com 這樣都有相同的qq.com的域名,具體的使用方法是把domain設(shè)置為相同部分的域名,具體如下:
document.cookie = "name=value;expires=date;path=/;domain=qq.com"
另外在使用cookie的時(shí)候我們還需要注意的是cookie的編碼問題,因?yàn)樵赾ookie是不支持逗號(hào)、空格、分號(hào)的,所以在設(shè)置cookie的時(shí)候,需要使用escape()將輸入的信息進(jìn)行轉(zhuǎn)碼,然后在要調(diào)用的時(shí)候使用unescape()來重新轉(zhuǎn)換回來.
WebSocket對(duì)象提供了用于創(chuàng)建和管理 WebSocket 連接,以及可以通過該連接發(fā)送和接收數(shù)據(jù)的 API。
WebSocket構(gòu)造器方法接受一個(gè)必須的參數(shù)和一個(gè)可選的參數(shù):
WebSocket WebSocket(in DOMString url, in optional DOMString protocols); WebSocket WebSocket(in DOMString url,in optional DOMString[] protocols);
url :表示要連接的URL。這個(gè)URL應(yīng)該為響應(yīng)WebSocket的地址。
protocoles 可以是一個(gè)單個(gè)的協(xié)議名字字符串或者包含多個(gè)協(xié)議名字字符串的數(shù)組。這些字符串用來表示子協(xié)議,這樣做可以讓一個(gè)服務(wù)器實(shí)現(xiàn)多種WebSocket子協(xié)議(例如你可能希望通過制定不同的協(xié)議來處理不同類型的交互)。如果沒有制定這個(gè)參數(shù),它會(huì)默認(rèn)設(shè)為一個(gè)空字符串。(可選)
構(gòu)造器方法可能拋出以下異常:
SECURITY_ERR 試圖連接的端口被屏蔽。
WebSocket protocol是HTML5一種新的協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,同時(shí)允許跨域通訊,是server push技術(shù)的一種很好的實(shí)現(xiàn)。
原生WebSocket API使用起來不太方便,我們使用Socket.io,它很好地封裝了webSocket接口,提供了更簡(jiǎn)單、靈活的接口,也對(duì)不支持webSocket的瀏覽器提供了向下兼容。具體可參閱前端常見跨域解決方案
H5新接口window.postMessage MDN
HTTP訪問控制CORS MDN
跨域資源共享CORS詳解
JavaScript跨域總結(jié)與解決辦法
詳解跨域(最全的解決方案)
淺談幾種跨域的方法
H5新接口webSocket MDN
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/94622.html
摘要:關(guān)于跨域,個(gè)人總結(jié)了以下幾種方法其中等方法常用,的方法既不復(fù)雜,也能兼容到幾乎所有瀏覽器,這真是極好的一種跨域方法。這個(gè)主要針對(duì)跨域訪問的情況兩個(gè)網(wǎng)頁一級(jí)域名相同,只是二級(jí)域名不同,瀏覽器允許通過設(shè)置共享。 關(guān)于跨域,個(gè)人總結(jié)了以下幾種方法 JSONP CORS WebSocket document.domain window.name location.hash postMessa...
摘要:前端開發(fā)中,跨域使我們經(jīng)常遇到的一個(gè)問題,也是面試中經(jīng)常被問到的一些問題,所以,這里,我們做個(gè)總結(jié)。同源策略限制了一下行為和無法讀取和對(duì)象無法獲取請(qǐng)求發(fā)送不出去常見的跨域場(chǎng)景所謂的同源是指,域名協(xié)議端口均為相同。 前端開發(fā)中,跨域使我們經(jīng)常遇到的一個(gè)問題,也是面試中經(jīng)常被問到的一些問題,所以,這里,我們做個(gè)總結(jié)。小小問題,不足擔(dān)心 原文地址:YOU-SHOULD-KNOW-JS 什么是...
摘要:介紹關(guān)于跨域問題有很多的解決方案,這里我們總結(jié)一下目前最通用最強(qiáng)大的解決方案。的工作組推薦了一種新的機(jī)制,即跨域資源共享,簡(jiǎn)稱。預(yù)檢請(qǐng)求用的請(qǐng)求方法是,表示這個(gè)請(qǐng)求是用來詢問的。頭信息里面,關(guān)鍵字段是,表示請(qǐng)求來自哪個(gè)源。 介紹 關(guān)于跨域問題有很多的解決方案,這里我們總結(jié)一下目前最通用最強(qiáng)大的解決方案:CORS。 W3C 的 Web 工作組推薦了一種新的機(jī)制,即跨域資源共享(Cross...
摘要:所以跨域請(qǐng)求分兩種簡(jiǎn)單請(qǐng)求和預(yù)檢請(qǐng)求。但對(duì)于第二個(gè)錯(cuò)誤,好像沒法向第一種那樣,將預(yù)檢請(qǐng)求轉(zhuǎn)變?yōu)楹?jiǎn)單請(qǐng)求,所以,只有尋找方法怎么在后端實(shí)現(xiàn)相應(yīng)的預(yù)檢請(qǐng)求,來返回一個(gè)狀態(tài)碼,告訴瀏覽器此次跨域請(qǐng)求可以繼續(xù)。 引子 自從從JAVA偽全棧轉(zhuǎn)前端以來,學(xué)習(xí)的路上就充滿了荊棘(奇葩問題),而涉及前后端分離這個(gè)問題,對(duì)cors的應(yīng)用不斷增多,暴露出的問題也接踵而至。這兩天動(dòng)手實(shí)踐基于Token的WE...
閱讀 2320·2021-09-29 09:42
閱讀 556·2021-09-06 15:02
閱讀 2595·2021-09-02 15:40
閱讀 2111·2019-08-30 14:23
閱讀 1860·2019-08-30 13:48
閱讀 1289·2019-08-26 12:01
閱讀 957·2019-08-26 11:53
閱讀 2141·2019-08-23 18:31