同源策略
同源策略是一種約定舔庶,是由Netscape提出的著名安全策略抛蚁。他是瀏覽器最核心、最基本的安全功能惕橙。
同源的定義
如果兩個(gè)頁(yè)面的協(xié)議瞧甩、端口、主機(jī)都相同弥鹦,則兩個(gè)頁(yè)面具有相同的源肚逸。
下面做一些說(shuō)明:
- 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比較:不是同源,因?yàn)?用的https彬坏,2用的是http朦促。屬于協(xié)議不同。
- 1和3比較:不是同源栓始,1未指定端口的時(shí)候务冕,默認(rèn)使用的是80,而3使用的是8000端口,屬于端口不同幻赚。
- 1和4比較:不是同源禀忆,域名不同。
- 1和5比較:雖然1部署在了該ip地址對(duì)應(yīng)的服務(wù)器落恼,但是依然不是同源箩退。
在不同源的情況下1站點(diǎn)里面的js腳本采用ajax讀取其他三個(gè)站點(diǎn)中的數(shù)據(jù)是會(huì)報(bào)錯(cuò)的。
注:IE瀏覽器未將不同端口加入同源策略的組成部分佳谦。
跨域
受同源策略的影響戴涝,不是 同源下的腳本不能操作其他源下面的對(duì)象。想要操作其他源下的對(duì)象就需要跨域。
為什么要跨域
比如某視頻網(wǎng)站由于數(shù)據(jù)太多啥刻,分布在了不同的服務(wù)器上奸鸯,所以需要突破同源策略,實(shí)現(xiàn)數(shù)據(jù)交互郑什。
跨域的實(shí)現(xiàn)
有以下幾種實(shí)現(xiàn)方式:
-
降域(document.domain):同源策略認(rèn)為域和子域?qū)儆诓煌挠颉?/p>
比如https://zz.zzs7.top和https://s7.zzs7.top府喳。雖然都屬于zzs7.top域名的子域名,但是他們屬于不同域蘑拯。
想讓上述兩個(gè)網(wǎng)頁(yè)之間通信,可以通過(guò)設(shè)置
document.damain='zzs7.top'
兜粘,來(lái)讓瀏覽器認(rèn)為他們?cè)谕瑯拥挠蛏昃健蓚€(gè)頁(yè)面都需設(shè)置。<script> document.domain = 'zzs7.top'; // 獲取父窗口中變量 </script>
注:可以進(jìn)行降域孔轴,不能升域剃法。
-
通過(guò)jsonp跨域:不同源雖然不能讀寫,但可以引用js路鹰。我們可以讓引用的js附帶數(shù)據(jù)來(lái)調(diào)用我們預(yù)先定義的函數(shù)贷洲,而數(shù)據(jù)當(dāng)作參數(shù)傳入。
<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 傳參一個(gè)回調(diào)函數(shù)名給后端晋柱,方便后端返回時(shí)執(zhí)行這個(gè)在前端定義的回調(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:跨域資源共享:一個(gè)W3C標(biāo)準(zhǔn)优构,它允許瀏覽器向跨源服務(wù)器發(fā)起
XMLHttpRequest請(qǐng)求
,和ajax同源的使用方法一致(區(qū)別在于對(duì)于跨域請(qǐng)求瀏覽器的請(qǐng)求會(huì)有附加的相關(guān)設(shè)置雁竞,用戶看不到)钦椭,分簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。通過(guò) location.hash:a欲與b跨域相互通信碑诉,通過(guò)中間頁(yè)c來(lái)實(shí)現(xiàn)彪腔。 三個(gè)頁(yè)面,不同域之間利用iframe的location.hash傳值进栽,相同域之間直接js訪問(wèn)來(lái)通信德挣。
window.name:window.name屬性的獨(dú)特之處:name值在不同的頁(yè)面(甚至不同域名)加載后依舊存在,并且可以支持非常長(zhǎng)的 name 值(2MB)快毛。
-
postMessage跨域:postMessage是HTML5 XMLHttpRequest Level 2中的API格嗅,且是為數(shù)不多可以跨域操作的window屬性之一,它可用于解決以下方面的問(wèn)題:
- 頁(yè)面和其打開的新窗口的數(shù)據(jù)傳遞
- 多窗口之間消息傳遞
- 頁(yè)面與嵌套的iframe消息傳遞
- 上面三個(gè)場(chǎng)景的跨域數(shù)據(jù)傳遞
用法:postMessage(data,origin)方法接受兩個(gè)參數(shù)
data: html5規(guī)范支持任意基本類型或可復(fù)制的對(duì)象祸泪,但部分瀏覽器只支持字符串吗浩,所以傳參時(shí)最好用JSON.stringify()序列化。
origin: 協(xié)議+主機(jī)+端口號(hào)没隘,也可以設(shè)置為"*"懂扼,表示可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"。
還有一些比的阀湿,比如可以通過(guò)nginx代理實(shí)現(xiàn)跨域等赶熟,就不在文章中細(xì)說(shuō)了,后續(xù)有機(jī)會(huì)詳細(xì)實(shí)踐一下每種方式陷嘴。