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