- 什麼是跨域
即‘同源策略’。簡單說,就是瀏覽器規定的安全功能。(自行Google,百度看看,因為我也一知半解)“協議+域名+埠”三者都相同,才同源,反著任意一個不同則跨域。同源策略限制的內容有(即同源才可以訪問,跨域則不行):
(1).Cookie,LocalStorage,IndexedDB等的儲存內容
(2).DOM節點。
(3)ajax請求傳送後,返回結果被瀏覽器攔截。
三個允許跨域載入的標籤:(1)<img src="xxxx"> (2)<link href="xxxx"> (3)<script src="xxx">
注意:跨域並不會請求發不出去,請求能傳送出去。服務端能收到請求並能正常返回結果,只是結果被瀏覽器攔截了。
2.跨域解決方法- jsonp
利用script標籤沒有跨域限制的漏洞
網頁可以得到其他源動態產生的JSON資料。JSONP請求一定要對方的伺服器做支援。只能get方法。
實現步驟可以自行google,百度。簡單說,宣告一個回撥函式傳給跨域伺服器,伺服器返回資料時帶上回撥函式 並做特殊拼接:回撥函式(‘要跨域獲取的目標資料’),客戶端宣告這個回撥函式的具體實現邏輯,當跨域伺服器返回這個回撥函式和目標資料的拼接時(即呼叫這個回撥函式),則可以操作目標資料了,並獲取。
2.cors
需要瀏覽器和後端同時支援.ie8和ie9需要通過XDomainRequest(啥東西,我不懂)來實現。
伺服器設定了Access-Control-Allow-Origin就可以開啟CORS。該屬性表示哪些域名可以訪問資源,如果設定萬用字元則表示所有網站都可以訪問。
前端分為簡單請求和複雜請求
簡單請求:get,head,post同時Content-Type僅限text/plain,multipart/form-data,application/x-www-form-urlencoded
複雜請求:不是簡單的就是複雜的。複雜請求在正式通訊前會增加一次HTTP查詢請求即預檢請求,請求方法為option來知道伺服器是否允許跨域請求。
3.postMessage
postMessage是Html5 XMLHttpRequest level2中的API,是為數不多的跨域操作的window屬性之一。作用:
(1)頁面和它開啟的新視窗的資料傳遞。
(2)多個視窗之間的訊息傳遞
(3)頁面和巢狀iframe訊息的傳遞
(4)上面三個場景的跨域資料傳遞
postMessage()方法允許來自不同源的指令碼採用非同步方式進行的有限通訊,可以實現跨文字檔,多視窗,跨域訊息的傳遞
實現:otherWindow.postMessage(‘messsage’,‘targetOrigin’,‘[transfer]’)
message:是將要傳送到其他window的資料。
targetOrigin:通過視窗的origin屬性來指定哪些視窗能接受到訊息事件,其值可以是‘*’表示無限制或者一個url。(協議,主機,地址或埠必須和目標視窗一致)
transfer:是一串和message同時傳送的Tranferable物件,這些物件的所有權將轉移給訊息接受方,而傳送方將步不再保有所有權。(不懂)// a.html <iframe src="b.html" frameborder="0" id="frame" onload="load()"></iframe//等它載入完觸發一個事件 //內嵌在a.html <script> function load() { let frame = document.getElementById('frame') frame.contentWindow.postMessage('我愛你', 'localhost:4000') //傳送資料 window.onmessage = function(e) { //接受返回資料 console.log(e.data) //我不愛你 } } </script>` `// b.html window.onmessage = function(e) { console.log(e.data) //我愛你 e.source.postMessage('我不愛你', e.origin) }
4.websocket(自己查)
5.Node中間代理(兩次跨域)
原理:同源策略是瀏覽器需要遵循的標準,而如果是伺服器向伺服器請求就無需遵循了。
a.接受客戶端請求。(代理伺服器)
b.將請求轉發給伺服器。
c.拿到伺服器響應資料(代理伺服器)
d.將資料轉發給客戶端
6.nginx 反向代理
7.window.name + iframe
window.name 屬性的獨特之處:name 值在不同的頁面(甚至不同域名)載入後依舊存在,並且可以支援非常長的 name 值(2MB)。// a.html(http://localhost:3000/b.html) <iframe src="c.html" frameborder="0" onload="load()" id="iframe"></iframe> <script> let first = true // onload事件會觸發2次,第1次載入跨域頁,並留存資料於window.name function load() { if(first){ // 第1次onload(跨域頁)成功後,切換到同域代理頁面 let iframe = document.getElementById('iframe'); iframe.src = /b.html'; first = false; }else{ // 第2次onload(同域b.html頁)成功後,讀取同域window.name中資料 console.log(iframe.contentWindow.name); } } </script> // c.html(http://localhost:4000/c.html) <script> window.name = '我不愛你' </script>
8.location.hash + iframe
實現原理: a.html 欲與 c.html 跨域相互通訊,通過中間頁 b.html 來實現。 三個頁面,不同域之間利用 iframe 的 location.hash 傳值,相同域之間直接 js 訪問來通訊。
- jsonp
具體實現步驟:一開始 a.html 給 c.html 傳一個 hash 值,然後 c.html 收到 hash 值後,再把 hash 值傳遞給 b.html,最後 b.html 將結果放到 a.html 的 hash 值中。
同樣的,a.html 和 b.html 是同域的
// a.html
<iframe src="c.html#iloveyou"></iframe>
<script>
window.onhashchange = function () { //檢測hash的變化
console.log(location.hash);
}
</script>
// b.html
<script>
window.parent.parent.location.hash = location.hash
//b.html將結果放到a.html的hash值中,b.html可通過parent.parent訪問a.html頁面
</script>
// c.html
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'b.html#idontloveyou';
document.body.appendChild(iframe);
9.document.domain + iframe
該方式只能用於二級域名相同的情況下,比如 a.test.com 和 b.test.com 適用於該方式。
只需要給頁面新增 document.domain ='test.com' 表示二級域名都相同就可以實現跨域。
實現原理:兩個頁面都通過 js 強制設定 document.domain 為基礎主域,就實現了同域。
// a.html
<body>
helloa
<iframe src="b.html" frameborder="0" onload="load()" id="frame"></iframe>
<script>
document.domain = 'zf1.cn'
function load() {
console.log(frame.contentWindow.a);
}
</script>
</body>
// b.html
<body>
hellob
<script>
document.domain = 'zf1.cn
var a = 100;
</script>
</body>
總結
CORS 支援所有型別的 HTTP 請求,是跨域 HTTP 請求的根本解決方案
JSONP 只支援 GET 請求,JSONP 的優勢在於支援老式瀏覽器,以及可以向不支援 CORS 的網站請求資料。
不管是 Node 中介軟體代理還是 nginx 反向代理,主要是通過同源策略對伺服器不加限制。
日常工作中,用得比較多的跨域方案是 cors 和 nginx 反向代理
本作品採用《CC 協議》,轉載必須註明作者和本文連結