整理前端最全跨域方案,工作面試不用愁(上)

關(guān)于前端跨域這個老生長談的問題琳猫,解決方案也是鋪天蓋地伟叛,但大家是否真正從原理上到實(shí)踐已經(jīng)完全掌握了呢?小郭今天將總結(jié)所有的跨域解決方案脐嫂,讓你在面試中收獲滿分痪伦。

本文將從跨域場景到跨域方案逐一說明侄榴,重點(diǎn)突出最常用跨域方案,讓你工作開發(fā)不用愁网沾。
由于本文涉及篇幅較長,因此分上下集講述蕊爵,力爭把最全面的跨域問題分享給大家辉哥。

概念

廣義跨域:一個域下的文檔或腳本試圖去請求另一個域下的資源,這被稱作為廣義上跨域攒射。
舉例:

  • 資源跳轉(zhuǎn): A鏈接醋旦、重定向、表單提交
  • 資源嵌入: <link>会放、<script>饲齐、<img>、<frame>等dom標(biāo)簽咧最,還有樣式中background:url()捂人、@font-face()等文件
  • 外鏈腳本請求: js發(fā)起的ajax請求、dom和js對象的跨域操作等

我們經(jīng)常討論的跨域是從狹義角度去理解矢沿,即:由瀏覽器同源策略限制的一類請求場景滥搭。先來解釋一下,什么是同源策略捣鲸?

同源策略/SOP(Same origin policy)是一種約定瑟匆,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能栽惶,如果缺少了同源策略愁溜,瀏覽器很容易受到XSS、CSFR等攻擊外厂。

所謂同源是指"協(xié)議+域名+端口"三者相同且必須相同冕象,即便兩個不同的域名指向同一個ip地址,也非同源酣衷。

一張圖說明同源策略限制的的場景:

以上就是關(guān)于跨域的原理交惯,那接下來整理一下前端都有哪些跨域解決方案,哪些是最常用的方案穿仪。

方案

  • 通過jsonp跨域
  • document.domain + iframe
  • 跨域location.hash + iframe
  • window.name + iframe跨域
  • postMessage跨域跨域資源共享(CORS)
  • nginx代理跨域
  • nodejs中間件代理跨域
  • WebSocket協(xié)議跨域

以上方案相信大家或多或少都有所了解席爽,在這里重點(diǎn)突出常用方案。

方案一:通過jsonp跨域

通常為了減輕web服務(wù)器的負(fù)載啊片,我們把js只锻、css,img等靜態(tài)資源分離到另一臺獨(dú)立域名的服務(wù)器上紫谷,在html頁面中再通過相應(yīng)的標(biāo)簽從不同域名下加載靜態(tài)資源齐饮,而被瀏覽器允許捐寥,基于此原理,我們可以通過動態(tài)創(chuàng)建script祖驱,再請求一個帶參網(wǎng)址實(shí)現(xiàn)跨域通信握恳。但只能實(shí)現(xiàn)get一種請求。不推薦

方案二:document.domain + iframe跨域

兩個頁面都通過js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域捺僻,就實(shí)現(xiàn)了同域乡洼。因此此方案僅限主域相同,子域不同的跨域應(yīng)用場景匕坯。不推薦

方案三: location.hash + iframe跨域

a欲與b跨域相互通信束昵,通過中間頁c來實(shí)現(xiàn)。 三個頁面葛峻,不同域之間利用iframe的location.hash傳值锹雏,相同域之間直接js訪問來通信。

實(shí)現(xiàn)方式:A域:a.html -> B域:b.html -> A域:c.html术奖,a與b不同域只能通過hash值單向通信礁遵,b與c也不同域也只能單向通信,但c與a同域腰耙,所以c可通過parent.parent訪問a頁面所有對象榛丢。因?yàn)閷?shí)現(xiàn)比較繁瑣,故不推薦

方案四: window.name + iframe跨域

window.name屬性的獨(dú)特之處在于name值在不同的頁面(甚至不同域名)加載后依舊存在挺庞,并且可以支持非常長的 name 值晰赞。

請求頁:http://www.domain1.com/a.html

var proxy = function(url, callback) {   
   var state = 0;    
   var iframe = document.createElement('iframe');    // 加載跨域頁面    
   iframe.src = url;    // onload事件會觸發(fā)2次,第1次加載跨域頁选侨,并留存數(shù)據(jù)于    
   window.name    iframe.onload = function() {       
    if (state === 1) {            // 第2次onload(同域proxy頁)成功后掖鱼,讀取同域window.name中數(shù)據(jù)            
      callback(iframe.contentWindow.name);            
      destoryFrame();        
    } else if (state === 0) {            // 第1次onload(跨域頁)成功后,切換到同域代理頁面            
      iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';                
      state = 1;       
    }   
 };    
  document.body.appendChild(iframe);    // 獲取數(shù)據(jù)以后銷毀這個iframe援制,釋放內(nèi)存戏挡;這也保證了安全(不被其他域frame js訪問)    
  function destoryFrame() {        
    iframe.contentWindow.document.write('');        
    iframe.contentWindow.close();        
    document.body.removeChild(iframe);    
  }
};// 請求跨域b頁面數(shù)據(jù)
proxy('http://www.domain2.com/b.html', function(data){    
  alert(data);
});

代理頁:http://www.domain1.com/proxy

中間代理頁,與a.html同域晨仑,無需添加內(nèi)容

被請求頁:http://www.domain2.com/b.html

<script>window.name = 'This is domain2 data!';</script>

通過iframe的src屬性由外域轉(zhuǎn)向本地域褐墅,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制洪己,但同時它又是安全操作妥凳。但操作依然復(fù)雜,不推薦使用

方案五:postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API答捕,且是為數(shù)不多可以跨域操作的window屬性之一逝钥,他可以解決這類問題:頁面和其打開的新窗口的數(shù)據(jù)傳遞;多窗口之間消息傳遞拱镐;頁面與嵌套的iframe消息傳遞艘款。

使用方法:postMessage(data,origin)方法接受兩個參數(shù)
data: html5規(guī)范支持任意基本類型或可復(fù)制的對象持际,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化哗咆。
origin: 協(xié)議+主機(jī)+端口號蜘欲,也可以設(shè)置為"*",表示可以傳遞給任意窗口岳枷,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"芒填。

請求頁:http://www.domain1.com/a.html

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
  var iframe = document.getElementById('iframe');    
  iframe.onload = function() { 
    var data = {           
      name: 'aym'        
    };        // 向domain2傳送跨域數(shù)據(jù) 
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');    };    // 接受domain2返回數(shù)據(jù) window.addEventListener('message', function(e) {       
   alert('data from domain2 ---> ' + e.data);   
 }, false);
</script>

接收頁:http://www.domain2.com/b.html

<script>   
 // 接收domain1的數(shù)據(jù)    
window.addEventListener('message', function(e) {        
  alert('data from domain1 ---> ' + e.data);        
  var data = JSON.parse(e.data);        
  if (data) {           
     data.number = 16;            // 處理后再發(fā)回domain1            
    window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');        }    }, false);
</script>

該方法雖然直接通過window屬性解決跨域,但其適用場景有限空繁,因此不推薦。

上集內(nèi)容到此結(jié)束朱庆。

總結(jié)一下:本篇主要帶大家弄清楚跨域的概念及跨域問題的來源盛泡,同時介紹了五種前端跨域問題的解決方案,但以上方案由于不同因素限制娱颊,所以均不推薦使用傲诵。下集內(nèi)容將講述前端最常用的幾種跨域解決方案,千萬不要錯過箱硕。

我是小郭拴竹,想了解更多前端知識歡迎關(guān)注公眾號“一郭鮮”,小郭將帶你在前端海洋里馳騁剧罩。另外栓拜,文章也將同步更新到公眾號,謝謝大家關(guān)注惠昔。

一郭鮮

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幕与,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子镇防,更是在濱河造成了極大的恐慌啦鸣,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件来氧,死亡現(xiàn)場離奇詭異诫给,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)啦扬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門中狂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人考传,你說我怎么就攤上這事吃型。” “怎么了僚楞?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵勤晚,是天一觀的道長枉层。 經(jīng)常有香客問我,道長赐写,這世上最難降的妖魔是什么鸟蜡? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮挺邀,結(jié)果婚禮上揉忘,老公的妹妹穿的比我還像新娘。我一直安慰自己端铛,他們只是感情好泣矛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著禾蚕,像睡著了一般您朽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上换淆,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天哗总,我揣著相機(jī)與錄音,去河邊找鬼倍试。 笑死讯屈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的县习。 我是一名探鬼主播涮母,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼准颓!你這毒婦竟也來了哈蝇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤攘已,失蹤者是張志新(化名)和其女友劉穎炮赦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體样勃,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吠勘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了峡眶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剧防。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辫樱,靈堂內(nèi)的尸體忽然破棺而出峭拘,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布鸡挠,位于F島的核電站辉饱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拣展。R本人自食惡果不足惜彭沼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望备埃。 院中可真熱鬧姓惑,春花似錦、人聲如沸按脚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辅搬。三九已至望众,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伞辛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工夯缺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚤氏,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓踊兜,卻偏偏與公主長得像竿滨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捏境,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 跨域資源共享 CORS 對于web開發(fā)來講于游,由于瀏覽器的同源策略,我們需要經(jīng)常使用一些hack的方法去跨域獲取資源...
    默默先生Alec閱讀 589評論 0 0
  • 1. 什么是跨域 跨域垫言,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本贰剥。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScri...
    cbw100閱讀 6,330評論 2 86
  • 前言 原文地址:前端跨域總結(jié)博主博客地址:Damonare的個人博客 正文 1. 什么是跨域筷频? 跨域一詞從字面意思...
    yo_yo_閱讀 500評論 0 5
  • 什么是跨域 跨域蚌成,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的凛捏,是瀏覽器對JavaScript實(shí)...
    Yaoxue9閱讀 1,299評論 0 6
  • 曾經(jīng) 偶然的遇見 帶來那么多執(zhí)念 時間消逝 你慢慢的淡出 在我的視線 淡忘在 我的心里面 本以為 不會再相見 想不...
    時光向前閱讀 187評論 0 4