摘要:瀏覽器同源政策以及跨域同源是指協(xié)議相同域名相同端口相同。同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。該協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。參考文獻(xiàn)瀏覽器同源政策及其規(guī)避方法詳解跨域問(wèn)題
瀏覽器同源政策以及JS跨域
同源是指協(xié)議相同、域名相同、端口相同。同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
同源策略主要限制下面三種情況
Cookie 無(wú)法讀取
DOM 無(wú)法獲得
AJAX 請(qǐng)求不能發(fā)送
同源策略的本意是為了保證用戶的信息安全。但有時(shí)也會(huì)帶來(lái)不便,下面我們來(lái)看一下怎樣規(guī)避同源的限制。
Cookie是服務(wù)器寫(xiě)入瀏覽器的一小段信息,只有同源的網(wǎng)頁(yè)才能共享。
當(dāng)兩個(gè)網(wǎng)頁(yè)的一級(jí)域名相同,只是二級(jí)域名不同的時(shí)候,我們可以通過(guò)設(shè)置document.domain來(lái)共享cookie
具體操作如下:
// 這兩個(gè)網(wǎng)頁(yè)的一級(jí)域名是相同的 http://h1.test.com http://h2.test.com //為兩個(gè)頁(yè)面設(shè)置相同的 document.domain document.domain = "test.com" // 這樣兩個(gè)網(wǎng)頁(yè)就能共享`Cookie`
document.domain 不能隨意設(shè)置,只能把document.domain設(shè)置成自身或更高一級(jí)的父域。
跨域文檔通信如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM,也無(wú)法進(jìn)行通信。典型的例子是iframe窗口和window.open方法打開(kāi)的窗口,它們與父窗口無(wú)法通信。
如果兩個(gè)窗口一級(jí)域名相同,只是二級(jí)域名不同,那么設(shè)置上一節(jié)介紹的document.domain屬性,就可以規(guī)避同源政策,拿到DOM。
關(guān)于通信,我們來(lái)看一下兩種解決方案:
片段識(shí)別符片段標(biāo)識(shí)符(fragment identifier)指的是,URL的#號(hào)后面的部分,如果只是改變片段標(biāo)識(shí)符,頁(yè)面不會(huì)重新刷新。
//父窗口可以把信息,寫(xiě)入子窗口的片段標(biāo)識(shí)符 var src = originURL + "#" + data; document.getElementById("myIFrame").src = src; //子窗口通過(guò)監(jiān)聽(tīng)hashchange事件得到通知 window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // ... } //同樣的,子窗口也可以改變父窗口的片段標(biāo)識(shí)符 parent.location.href= target + "#" + hash;window.postMessage
window.postMessage 是HTML5為了解決這個(gè)問(wèn)題,引入了一個(gè)全新的API,無(wú)論兩個(gè)窗口是否同源,都允許一個(gè)窗口向另一個(gè)窗口發(fā)送數(shù)據(jù)。
語(yǔ)法:
// otherWindow 其他窗口的一個(gè)引用,比如iframe的contentWindow屬性、執(zhí)行window.open返回的窗口對(duì)象 //message 將要發(fā)送到其他 window的數(shù)據(jù) //targetOrigin 接收消息的窗口的源(origin) otherWindow.postMessage(message, targetOrigin)
其他window可以監(jiān)聽(tīng)message
//監(jiān)聽(tīng) message 事件 window.addEventListener("message", receiveMessage, false); //事件對(duì)象有一些常用的屬性 //data 從其他 window 中傳遞過(guò)來(lái)的對(duì)象 //origin 消息發(fā)送方窗口的 origin //source 對(duì)發(fā)送消息的窗口對(duì)象的引用 function receiveMessage(event){ var origin = event.origin; //對(duì)發(fā)送消息的源進(jìn)行驗(yàn)證 if (origin !== "http://example.org:8080") return; // ... }
實(shí)例:
窗口A : http://xiaoxiong.com
窗口B : http://miaomiao.com
顯然這兩個(gè)窗口不同源,不能通信,現(xiàn)在我們用postMessage進(jìn)行通信。
//Awindow、Bwindow分別表示對(duì) A B 窗口對(duì)象的引用 //B窗口向A窗口發(fā)消息 //如果A窗口的協(xié)議、主機(jī)地址或端口這三者的任意一項(xiàng)不匹配targetOrigin提供的值,消息就不能發(fā)送成功 //注意是用 Awindow 調(diào)用 postMessage 方法 Awindow.postMessage("hello!","http://xiaoxiong.com"); //在A中設(shè)置監(jiān)聽(tīng)事件 window.addEventListener("message", receiveMessage, false); function receiveMessage(event){ console.log(event.origin);//http://miaomiao.com console.log(event.source);// Bwindow console.log(event.data);// hello! }AJAX
AJAX請(qǐng)求是我們經(jīng)常用到的異步請(qǐng)求方法,但是AJAX請(qǐng)求是不能跨域的。
下面我們看一下常見(jiàn)的AJAX跨域方法
JSONP基本思想是,網(wǎng)頁(yè)通過(guò)添加一個(gè)元素,向服務(wù)器請(qǐng)求JSON數(shù)據(jù),這種做法不受同源政策限制;服務(wù)器收到請(qǐng)求后,將數(shù)據(jù)放在一個(gè)指定名字的回調(diào)函數(shù)里傳回來(lái)。
function addScript(src) { var script = document.createElement("script"); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script, body.firstChild); } window.onload = function () { //請(qǐng)求的查詢字符串有一個(gè)callback參數(shù),用來(lái)指定回調(diào)函數(shù)的名字,這對(duì)于JSONP是必需的 addScript("http://test.com/a?callback=handler"); } //請(qǐng)求回來(lái)數(shù)據(jù)作為回調(diào)函數(shù)的參數(shù) //作為參數(shù)的JSON數(shù)據(jù)被視為JavaScript對(duì)象 不用進(jìn)行轉(zhuǎn)換 function handler(data) { console.log(data); };
JSONP的優(yōu)點(diǎn):不受同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中都可以運(yùn)行;并且在請(qǐng)求完畢后可以通過(guò)調(diào)用callback的方式回傳結(jié)果。
JSONP的缺點(diǎn):它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求;它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁(yè)面之間如何進(jìn)行JavaScript調(diào)用的問(wèn)題。
WebSocketWebSocket是一種通信協(xié)議,使用ws://(非加密)和wss://(加密)作為協(xié)議前綴。該協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。
實(shí)例:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
上面代碼中,有一個(gè)字段是Origin,表示該請(qǐng)求的請(qǐng)求源(origin),即發(fā)自哪個(gè)域名。
正是因?yàn)橛辛?b>Origin這個(gè)字段,所以WebSocket才沒(méi)有實(shí)行同源政策。因?yàn)榉?wù)器可以根據(jù)這個(gè)字段,判斷是否許可本次通信。如果該域名在白名單內(nèi),服務(wù)器就會(huì)做出如下回應(yīng)。
跨域資源共享 是官方的跨域解決方案。
整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺(jué)。
基本思想
CORS定義了必須在訪問(wèn)跨域資源時(shí),瀏覽器與服務(wù)器應(yīng)該如何溝通。CORS背后的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定請(qǐng)求或響應(yīng)是應(yīng)該成功還是失敗。
基本流程
瀏覽器發(fā)現(xiàn)是跨源AJAX請(qǐng)求,瀏覽器就直接發(fā)出CORS請(qǐng)求。具體來(lái)說(shuō),就是在頭信息之中,增加一個(gè)Origin字段。
GET /cors HTTP/1.1 Origin: http://xiaoxiong.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
上面的頭信息中,Origin字段用來(lái)說(shuō)明,本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 域名 + 端口)。服務(wù)器根據(jù)這個(gè)值,決定是否同意這次請(qǐng)求。
如果Origin指定的源,不在許可范圍內(nèi),服務(wù)器會(huì)返回一個(gè)正常的HTTP回應(yīng)。瀏覽器發(fā)現(xiàn),這個(gè)回應(yīng)的頭信息沒(méi)有包含Access-Control-Allow-Origin字段,就知道出錯(cuò)了,從而拋出一個(gè)錯(cuò)誤,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲。注意,這種錯(cuò)誤無(wú)法通過(guò)狀態(tài)碼識(shí)別,因?yàn)镠TTP回應(yīng)的狀態(tài)碼有可能是200。
如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng),會(huì)多出幾個(gè)頭信息字段。
Access-Control-Allow-Origin: http://xiaoxiong.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin
該字段是必須的。它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。
CORS和JSONP對(duì)比,更為先進(jìn)、方便和可靠。
1、 JSONP只能實(shí)現(xiàn)GET請(qǐng)求,而CORS支持所有類型的HTTP請(qǐng)求。 2、 使用CORS,開(kāi)發(fā)者可以使用普通的XMLHttpRequest發(fā)起請(qǐng)求和獲得數(shù)據(jù),比起JSONP有更好的錯(cuò)誤處理。 3、 JSONP主要被老的瀏覽器支持,它們往往不支持CORS,而絕大多數(shù)現(xiàn)代瀏覽器都已經(jīng)支持了CORS)。 4、 jsonp在調(diào)用失敗的時(shí)候不會(huì)返回各種HTTP狀態(tài)碼。 5、在請(qǐng)求完畢后可以通過(guò)調(diào)用callback的方式回傳結(jié)果。將回調(diào)方法的權(quán)限給了調(diào)用方。這個(gè)就相當(dāng)于將controller層和view層終于分開(kāi)了。我提供的jsonp服務(wù)只提供純服務(wù)的數(shù)據(jù),至于提供服務(wù)以后的頁(yè)面渲染和后續(xù)view操作都由調(diào)用者來(lái)自己定義就好了。如果有兩個(gè)頁(yè)面需要渲染同一份數(shù)據(jù),你們只需要有不同的渲染邏輯就可以了,邏輯都可以使用同 一個(gè)jsonp服務(wù)。
參考文獻(xiàn)
瀏覽器同源政策及其規(guī)避方法
詳解js跨域問(wèn)題
window.postMessage
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84269.html
摘要:概述同源策略是對(duì)代碼能夠操作哪些內(nèi)容的一條完整的安全限制,也是由提出的一個(gè)著名的安全策略。同源策略的目的同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。 [TOC] 1、概述 同源策略是對(duì)JavaScript代碼能夠操作哪些WEB內(nèi)容的一條完整的安全限制,也是由Netscape提出的一個(gè)著名的安全策略。所謂同源簡(jiǎn)單來(lái)說(shuō)就是三個(gè)相同,**1、域名相同2、協(xié)議相同3、端口...
摘要:概述同源策略是對(duì)代碼能夠操作哪些內(nèi)容的一條完整的安全限制,也是由提出的一個(gè)著名的安全策略。同源策略的目的同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。 [TOC] 1、概述 同源策略是對(duì)JavaScript代碼能夠操作哪些WEB內(nèi)容的一條完整的安全限制,也是由Netscape提出的一個(gè)著名的安全策略。所謂同源簡(jiǎn)單來(lái)說(shuō)就是三個(gè)相同,**1、域名相同2、協(xié)議相同3、端口...
摘要:但是如果是一級(jí)域名相同,二級(jí)及以上域名不同的網(wǎng)頁(yè)可以通過(guò)設(shè)置來(lái)共享。設(shè)置有兩種方式前端腳本中設(shè)置服務(wù)器接口設(shè)置時(shí)指定所屬的域名為一級(jí)域名。服務(wù)器檢查過(guò)預(yù)檢請(qǐng)求頭之后,確認(rèn)允許跨域請(qǐng)求,就可以做出回應(yīng)。 一、跨域問(wèn)題產(chǎn)生的原因 根本原因是由于瀏覽器的同源政策。 1.1.同源政策 同源政策由網(wǎng)景公司(Netscape)1995年引入瀏覽器。目前所有瀏覽器都實(shí)行這個(gè)政策。所謂同源是指三個(gè)相同...
摘要:補(bǔ)充同源策略還應(yīng)該對(duì)一些特殊情況做處理,比如限制協(xié)議下腳本的訪問(wèn)權(quán)限。注意,該請(qǐng)求的查詢字符串有一個(gè)參數(shù),用來(lái)指定回調(diào)函數(shù)的名字,這對(duì)于是必需的。 1 前言: 首先對(duì)參考文章作者表示感謝,你們的經(jīng)驗(yàn)總結(jié)給我們這些新手提供了太多資源。本文致力于解決AJAX的CORS問(wèn)題,我在邏輯上進(jìn)行了梳理:首先,系統(tǒng)的總結(jié)了CORS問(wèn)題的起源---同源策略;其次,介紹JSONP這種僅能支持GET請(qǐng)求的...
摘要:補(bǔ)充同源策略還應(yīng)該對(duì)一些特殊情況做處理,比如限制協(xié)議下腳本的訪問(wèn)權(quán)限。注意,該請(qǐng)求的查詢字符串有一個(gè)參數(shù),用來(lái)指定回調(diào)函數(shù)的名字,這對(duì)于是必需的。 1 前言: 首先對(duì)參考文章作者表示感謝,你們的經(jīng)驗(yàn)總結(jié)給我們這些新手提供了太多資源。本文致力于解決AJAX的CORS問(wèn)題,我在邏輯上進(jìn)行了梳理:首先,系統(tǒng)的總結(jié)了CORS問(wèn)題的起源---同源策略;其次,介紹JSONP這種僅能支持GET請(qǐng)求的...
閱讀 1283·2023-04-26 01:38
閱讀 1475·2021-11-15 11:39
閱讀 3264·2021-09-22 15:43
閱讀 2665·2019-08-30 15:55
閱讀 2061·2019-08-30 14:17
閱讀 2864·2019-08-29 14:16
閱讀 3075·2019-08-26 18:36
閱讀 2620·2019-08-26 12:19