同源策略
同源策略是一種約定,是由Netscape提出的著名安全策略。他是瀏覽器最核心、最基本的安全功能。
同源的定義
如果兩個頁面的協(xié)議、端口、主機都相同,則兩個頁面具有相同的源。
下面做一些說明:
- https://zz.zzs7.top/mysql-optimization.html
- http://zz.zzs7.top/mysql-optimization.html
- https://zz.zzs7.top:8000/mysql-optimization.html
- https://s7.zzs7.top/mysql-optimization.html
- https://104.125.11.39/mysql-optimization.html
上面的鏈接中:
- 1和2比較:不是同源,因為1用的https,2用的是http。屬于協(xié)議不同。
- 1和3比較:不是同源,1未指定端口的時候,默認使用的是80,而3使用的是8000端口,屬于端口不同。
- 1和4比較:不是同源,域名不同。
- 1和5比較:雖然1部署在了該ip地址對應(yīng)的服務(wù)器,但是依然不是同源。
在不同源的情況下1站點里面的js腳本采用ajax讀取其他三個站點中的數(shù)據(jù)是會報錯的。
注:IE瀏覽器未將不同端口加入同源策略的組成部分。
跨域
受同源策略的影響,不是 同源下的腳本不能操作其他源下面的對象。想要操作其他源下的對象就需要跨域。
為什么要跨域
比如某視頻網(wǎng)站由于數(shù)據(jù)太多,分布在了不同的服務(wù)器上,所以需要突破同源策略,實現(xiàn)數(shù)據(jù)交互。
跨域的實現(xiàn)
有以下幾種實現(xiàn)方式:
-
降域(document.domain):同源策略認為域和子域?qū)儆诓煌挠颉?/p>
比如https://zz.zzs7.top和https://s7.zzs7.top。雖然都屬于zzs7.top域名的子域名,但是他們屬于不同域。
想讓上述兩個網(wǎng)頁之間通信,可以通過設(shè)置
document.damain='zzs7.top',來讓瀏覽器認為他們在同樣的域。兩個頁面都需設(shè)置。<script> document.domain = 'zzs7.top'; // 獲取父窗口中變量 </script>
注:可以進行降域,不能升域。
-
通過jsonp跨域:不同源雖然不能讀寫,但可以引用js。我們可以讓引用的js附帶數(shù)據(jù)來調(diào)用我們預(yù)先定義的函數(shù),而數(shù)據(jù)當(dāng)作參數(shù)傳入。
<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 傳參一個回調(diào)函數(shù)名給后端,方便后端返回時執(zhí)行這個在前端定義的回調(diào)函數(shù) script.src = 'http://zz.zzs7.top/login?user=admin&callback=handleCallback'; document.head.appendChild(script); // 回調(diào)執(zhí)行函數(shù) function handleCallback(res) { alert(JSON.stringify(res)); } </script> CORS:跨域資源共享:一個W3C標準,它允許瀏覽器向跨源服務(wù)器發(fā)起
XMLHttpRequest請求,和ajax同源的使用方法一致(區(qū)別在于對于跨域請求瀏覽器的請求會有附加的相關(guān)設(shè)置,用戶看不到),分簡單請求和非簡單請求。通過 location.hash:a欲與b跨域相互通信,通過中間頁c來實現(xiàn)。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通信。
window.name:window.name屬性的獨特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。
-
postMessage跨域:postMessage是HTML5 XMLHttpRequest Level 2中的API,且是為數(shù)不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:
- 頁面和其打開的新窗口的數(shù)據(jù)傳遞
- 多窗口之間消息傳遞
- 頁面與嵌套的iframe消息傳遞
- 上面三個場景的跨域數(shù)據(jù)傳遞
用法:postMessage(data,origin)方法接受兩個參數(shù)
data: html5規(guī)范支持任意基本類型或可復(fù)制的對象,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化。
origin: 協(xié)議+主機+端口號,也可以設(shè)置為"*",表示可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"。
還有一些比的,比如可以通過nginx代理實現(xiàn)跨域等,就不在文章中細說了,后續(xù)有機會詳細實踐一下每種方式。