? ? 跨域:只要協(xié)議疲牵、域名承二、端口有任何一個不同,都被當(dāng)作是不同的域纲爸;
? ??前端碰上跨域的問題應(yīng)該算是十分常見亥鸠,比如地址映射,訪問外部網(wǎng)路接口等等识啦,而且面試中常常會問到這個负蚊,所以做下總結(jié):
1、瀏覽器有一個同源策略颓哮,其一是不能通過ajax的方法去請求不同源中的文檔家妆。其二是瀏覽器中不同域的框架之間是不能進行js的交互操作的。不同的框架之間是可以獲取window對象的冕茅,但卻無法獲取相應(yīng)的屬性和方法伤极;
理解:不同域的文檔以及js,你可以獲取這個對象姨伤,但是你無法確定對象中的元素以及方法
解決:
document.domain跨域 - iframe :
在當(dāng)前頁(a.xxx.com)的js與iframe(b.xxx.com)的js中用document.domain設(shè)置同一個域名(xxx.com)哨坪,這樣兩個頁面就屬于同樣一個域名下,可以進行相互調(diào)用
缺點:兩個域名必須屬于同一個基礎(chǔ)域名姜挺,而且所用的協(xié)議齿税,端口都要一致彼硫,否則無法利用document.domain進行跨域
2炊豪、hash:?URL有一部分被稱為hash(就是#號及其后面的字符)-瀏覽器錨點定位凌箕,修改這個部分會產(chǎn)生瀏覽器歷史記錄,但是不影響請求發(fā)送
location.hash跨域 -?iframe:
(1)父傳子:
? ? 修改iframe中src的#后綴词渤,在iframe中監(jiān)聽#后綴變化獲取
(2)子傳父:
? ? 在iframe中新增一個iframe牵舱,域名為父級的域名,然后通過parent修改#后綴:
? ??parent.parent.location.hash = self.location.hash.substring(1)
缺點:數(shù)據(jù)直接暴露在了url中缺虐;數(shù)據(jù)容量和類型都有限
注意:IE芜壁、chrome的安全機制無法修改parent.location.hash,需要parent.location.hash = 'data'來try catch判斷是否可以執(zhí)行
3高氮、postMessage跨域:
使用方法:
父級使用: otherWindow.postMessage(message, targetOrigin);
iframe.contentWindow.postMessage('xxx', 路徑)
otherWindow:指目標(biāo)窗口慧妄,也就是給哪個window發(fā)消息,是 window.frames 屬性的成員或者由 window.open 方法創(chuàng)建的窗口
message:? 是要發(fā)送的消息剪芍,類型為 String塞淹、Object (IE8、9 不支持)
targetOrigin:? 是限定消息接收范圍
子級使用:window.addEventListener(“message”, function(event){})
event.data : 是傳遞過來的數(shù)據(jù)
event.origin :?是調(diào)用postMessage方法的窗口的源URL(包括協(xié)議罪裹、域名饱普、端口號)
event.source :?是發(fā)送消息的窗口對象
注意:要確定iframe創(chuàng)建完畢后加入監(jiān)聽,否則可能監(jiān)聽不到傳遞的信息状共;如果iframe中的同源頁面需要使用可以在子頁面中把數(shù)據(jù)存入緩存
4套耕、jsonp跨域:
適用:單純獲取不同源網(wǎng)頁的數(shù)據(jù)
<script src="xxx?callback=方法名"></script>
如上,jsonp時通過script導(dǎo)入時的回調(diào)函數(shù)進行數(shù)據(jù)獲取的
$.getJSON('xxx?callback=?,function(jsondata)'){
? ? ? ? //處理獲得的json數(shù)據(jù)
?})
query會自動生成一個全局函數(shù)來替換callback=?中的問號峡继,之后獲取到數(shù)據(jù)后又會自動銷毀-實際上就是起一個臨時代理函數(shù)的作用
$.getJSON方法會自動判斷是否跨域冯袍,不跨域的話,就調(diào)用普通的ajax方法碾牌;跨域的話颠猴,則會以異步加載js文件的形式來調(diào)用jsonp的回調(diào)函數(shù)
$.ajax({
? url: 'xxx',
? type: 'get',
? dataType: 'jsonp', // 請求方式為jsonp
? jsonpCallback: "回調(diào)函數(shù)",// 自定義回調(diào)函數(shù)名??
? data: {}
})
優(yōu)點:它不像XMLHttpRequest對象實現(xiàn)的Ajax請求那樣受到同源策略的限制;它的兼容性更好小染,在更加古老的瀏覽器中都可以運行翘瓮,不需要XMLHttpRequest或ActiveX的支持;并且在請求完畢后可以通過調(diào)用callback的方式回傳結(jié)果
缺點:它只支持GET請求而不支持POST等其它類型的HTTP請求裤翩;它只支持跨域HTTP請求這種情況资盅,不能解決不同域的兩個頁面之間如何進行JavaScript調(diào)用的問題
5、cros跨域
cros跨域的實現(xiàn)主要時依靠后端實現(xiàn)踊赠,前端只要調(diào)用方法即可呵扛,不多做介紹
6、window.name跨域
window.name:?
????在一個窗口(window)的生命周期內(nèi),窗口載入的所有的頁面都是共享一個window.name的筐带;
????每個頁面對window.name都有讀寫的權(quán)限今穿;
????window.name是持久存在一個窗口載入過的所有頁面中的,并不會因新頁面的載入而進行重置伦籍;
????可以存儲不超過2M的數(shù)據(jù)蓝晒,只能是String格式的數(shù)據(jù)
與document.domain類似腮出,window.name的跨域需要使用一個中間iframe:
var iframe = document.getElementById('iframe');
????iframe.onload = function () {
????var window = iframe .contentWindow;
????console.log(window.name);
?}
iframe.src = '同源地址'
與 document.domain 方法相比,window.name放寬了域名后綴要相同的限制芝薇,可以從任意頁面獲取 string 類型的數(shù)據(jù)
7胚嘲、Vue中的proxy跨域(常用):
現(xiàn)在Vue項目下通常都會有vue.config.js文件作為項目的配置用,如果沒有可以在根目錄下新建洛二,會自動讀炔雠;
通過配置proxy就可以成功跨域:
devServer: {
? ? proxy: {? // 配置跨域
????'/api': {
? ? ? ? target: 'xxxx',// 真實接口
? ? ? ? changOrigin:true,// 允許跨域? ? ? ??
? ? ? ? pathRewrite: {i
? ? ? ? ? '^/api': ''
? ? ? ? }
? ? ? },
????}
?},
通過配置晾嘶,真實的路徑會被掩蓋妓雾,瀏覽器訪問的地址將會被重寫成真正的路徑,安全性較高
注意: 是否形成跨域垒迂,在前端的判斷是根據(jù)URL的路徑(window.location.protocol + window.location.hos)判斷的君珠,頭部的域就是判斷的標(biāo)準(zhǔn);
如果是協(xié)議和端口造成的跨域問題“前臺”是無能為力的娇斑;