前言
這幾天的工作中,碰到了一個完全不同域之間的跨域問題,發現自己竟然無法確定能不能實現跨域,可見基礎知識完全被拋之腦後了,趁週末整理一下。
為什麼會存在跨域
跨域是因為瀏覽器有同源策略,同源策略的定義是協議、域名、埠都要一致。 在跨域的情況下,瀏覽器出於安全考慮,會限制不同域之間的資料或DOM互動行為,如:
-
Cookie、LocalStorage 和 IndexDB 無法讀取。
-
DOM 無法獲得。
-
AJAX 請求不能傳送。
關於同源策略的具體概念請參考MDN。
為什麼需要同源策略呢。那我們試想一下如果瀏覽器沒有同源策略的情況。
打個最基本的比方,現在你新建了一個站點:
假如沒有跨域限制,那是不是可以隨便讀取天貓的cookie,localStorage, indexDb 等資訊,如果這些資訊裡有使用者名稱和密碼或其他敏感資訊,剛好又沒有加密的話,那豈不是都能拿到,這怎麼可能。
假如沒有跨域限制,你把iframe的src指向天貓,讓使用者去登陸,然後你就可以獲取iframe裡面的dom元素,那豈不是賬號密碼唾手可得。可以訪問dom的話,只要iframe引入其他公司的站點,想怎麼改就怎麼改,那好多公司都要倒閉了。
假如沒有跨域限制,就可以向天貓等站點發請求,那豈不是可以隨便提交別人的訂單。這明顯不合理啊。世界會亂。
但跨域問題總要解決的,因為有時候業務中確實需要跨域
下面列出八種跨域解決方案
jsonp
原理:使用script標籤,src的值為後端某個檔案,加上callback引數。返回一段js字串。
<!-- fn 需自定義 -->
<script src="http:xx/xx.php?callback=fn"></script>
複製程式碼
缺點:只能用於 get 請求。如果需要 post,可以試試用 form 提交來 hack。
document.domain
原理:通過設定document.domain來跨域。
缺點:只適用於主域相同,子域不同的業務場景。
hash
原理:利用hash改變,頁面不會重新整理的特點。父視窗在iframe的src上增加hash值,並在子視窗監聽 hashChange事件。
缺點:只能通過 hash 傳遞有效資訊, 只能設定字串型別。
原理:在一個視窗(window)的生命週期內,視窗載入的所有的頁面都是共享一個 window.name。
通常做法是用一個隱藏的iframe 去載入一個同域的代理檔案:proxy.html,在代理檔案中設定window.name,再動態替換iframe的src為外域的url,這樣就可以通過window.name傳遞有效資訊。
因為proxy.html 和 真實需要跳轉的外域 url 都是在同一個iframe下,window物件是同一個。
如果需要回傳資料給父視窗,就反著來。可以先用iframe開啟外域的url,在外域的檔案中設定 window.name後,再跳轉到 同域的 proxy.html。父視窗這時再獲取
缺點:需要一個代理檔案 proxy.html。window.name 只能設定字串型別。
postMessage
原理:說不清, 此乃瀏覽器自帶 API。具體用法就不介紹了。
缺點:接收方需要監聽 message 事件。
webSocket
原理:webScoket採用的是 ws:// 或 wss:// 協議,非 http 協議。協議不實行同源政策,只要伺服器支援,就可以通過它進行跨源通訊,需要在服務端設定白名單。
缺點:說不清
CORS
原理:說不清
缺點:對於複雜請求,如非get,或資料格式為json的請求, 會觸發兩次請求。一次為 OPTIONS 預檢請求,第二次才是正式請求。
伺服器代理跨域
原理:瞭解一點 — 利用後端訪問介面不存在跨域的特點。
缺點:說不清