說說跨域那些事兒

首先糾正一個(gè)誤區(qū),跨域并非瀏覽器限制了發(fā)起跨站請(qǐng)求的這種能力,恰恰相反枫浙,我們可以發(fā)出請(qǐng)求妆偏,服務(wù)端也可以接收到請(qǐng)求并正常返回?cái)?shù)據(jù)刃鳄,只不過在返回之后瀏覽器會(huì)阻止非同源數(shù)據(jù)(response),從而在控制臺(tái)打出一系列報(bào)錯(cuò)信息钱骂。

原文地址:說說跨域那些事兒叔锐,遷移到簡書上來和大家共享

兼容性查找

文章中會(huì)涉及一系列兼容性的圖解(mdn & can i use)和一些專有名詞(mdn),可以通過兩個(gè)渠道來查看

跨域類型

定義就不說了见秽,從字面也可以看其含義愉烙,首先我們認(rèn)識(shí)下哪些情況屬于跨域,可以分為以下幾點(diǎn):

  • 協(xié)議不同解取,如http, https步责;
  • 端口不同;
  • 主域相同,子域不同蔓肯;
  • 主域不同遂鹊;
  • ip地址和域名之間也算是跨域,瀏覽器不會(huì)自動(dòng)做ip域名的映射蔗包;

解決方案

  • document.domain
  • window.name
  • jsonp
  • postMessage
  • cors

document.domain

  • 關(guān)鍵點(diǎn)
    • 跨域分為兩種秉扑,一種xhr不能訪問不同源的文檔,另一種是不同window之間不能進(jìn)行交互操作;
    • document.domain主要是解決第二種情況调限,且只能適用于主域相同子域不同的情況舟陆;
    • document.domain的設(shè)置是有限制的,我們只能把document.domain設(shè)置成自身或更高一級(jí)的父域旧噪,且主域必須相同吨娜。例如:a.b.example.com中某個(gè)文檔的document.domain可以設(shè)成a.b.example.com、b.example.com 淘钟、example.com中的任意一個(gè)宦赠,但是不可以設(shè)成c.a.b.example.com,因?yàn)檫@是當(dāng)前域的子域米母,也不可以設(shè)成baidu.com勾扭,因?yàn)橹饔蛞呀?jīng)不相同了。
  • 兼容性:所有瀏覽器都支持铁瞒;
  • 優(yōu)點(diǎn):
    • 可以實(shí)現(xiàn)不同window之間的相互訪問和操作妙色;
  • 缺點(diǎn):
    • 只適用于父子window之間的通信,不能用于xhr慧耍;
    • 只能在主域相同且子域不同的情況下使用身辨;
  • 使用方式
    • a(當(dāng)前頁面或父頁面)頁面中加入document.domain = 'example.com';
    • b(當(dāng)前頁面或子頁面)頁面中加入document.domain = 'example.com';
    • a頁面訪問b頁面里面的數(shù)據(jù)或者方法;

window.name

  • 關(guān)鍵點(diǎn):window.name在頁面的生命周期里共享一個(gè)window.name;
  • 兼容性:所有瀏覽器都支持芍碧;
  • 優(yōu)點(diǎn):
    • 最簡單的利用了瀏覽器的特性來做到不同域之間的數(shù)據(jù)傳遞煌珊;
    • 不需要前端和后端的特殊配制;
  • 缺點(diǎn):
    • 大小限制:window.name最大size是2M左右泌豆,不同瀏覽器中會(huì)有不同約定定庵;
    • 安全性:當(dāng)前頁面所有window都可以修改,很不安全踪危;
    • 數(shù)據(jù)類型:傳遞數(shù)據(jù)只能限于字符串蔬浙,如果是對(duì)象或者其他會(huì)自動(dòng)被轉(zhuǎn)化為字符串,如下贞远;


  • 使用方式:修改window.name的值即可畴博;

jsonp

  • 關(guān)鍵點(diǎn):瀏覽器對(duì)XHR做了同源策略,但并沒有將這種方式延續(xù)到script上(其實(shí)還有iframe蓝仲,img等)绎晃,從而可以利用動(dòng)態(tài)script標(biāo)簽技術(shù)來做到跨域請(qǐng)求的作用蜜唾。至于為什么會(huì)這樣設(shè)計(jì),本人也不太清楚庶艾,有可能是歷史遺跡(漏洞),有可能是某些方面的技術(shù)瓶頸擎勘,也有可能是為了滿足某些需求專門定制的咱揍,總之這項(xiàng)技術(shù)方案我們過去可以用,現(xiàn)在可以用就ok棚饵,至于將來應(yīng)該也是會(huì)存在的煤裙,畢竟現(xiàn)在已經(jīng)應(yīng)用在很多家站點(diǎn)上,就算會(huì)廢棄噪漾,也會(huì)有一段時(shí)間迭代硼砰。
  • 兼容性:所有瀏覽器都兼容這種方式;
  • 優(yōu)點(diǎn):很明顯前端可以很輕松的做到跨域請(qǐng)求欣硼;
  • 缺點(diǎn)
    • 只能通過GET方式請(qǐng)求题翰,一方面是參數(shù)長度有限制,二是安全性比較差诈胜;
    • 后端需要知道前端的cb是什么樣的結(jié)構(gòu)豹障,主要在參數(shù)和回調(diào)名;
    • 后端需要進(jìn)行參數(shù)和cb的拼接然后才能執(zhí)行焦匈;
  • 使用方式
/** 前端生成script標(biāo)簽血公,并將src中傳入需要執(zhí)行的callback **/
<script type="text/javascript">
    var ele = document.createElement('script');
    ele.type = "text/javascript"
    ele.src = "http://example.com?jsonp=cb";
    document.body.appendChild(ele);
</script>


/** 后端接到參數(shù)后給callback加入?yún)?shù)并執(zhí)行 **/
<?php
    $cb = $_GET['cb'];
    $data = array('test1', 'test2', 'test3');
    echo $cb.'('.json_encode($data).')';
?>

postMessage

  • 關(guān)鍵點(diǎn):postMessage是h5引入的一個(gè)新概念,現(xiàn)在也在進(jìn)一步的推廣和發(fā)展中缓熟,他進(jìn)行了一系列的封裝累魔,我們可以通過window.postMessage的方式進(jìn)行使用,并可以監(jiān)聽其發(fā)送的消息够滑;
  • 兼容性:下圖是postMessage的兼容圖垦写,移動(dòng)端可以放心用,但是pc端需要做降級(jí)處理版述,具體可以根據(jù)文中介紹的這幾種跨域方式來則情選擇梯澜;


    poseMessage兼容性
  • 優(yōu)點(diǎn)
    • 不需要后端介入就可以非常簡單的的做到跨域,一個(gè)函數(shù)外加兩個(gè)參數(shù)(請(qǐng)求url渴析,發(fā)送數(shù)據(jù))就可以搞定晚伙;
    • 移動(dòng)端兼容性好;
  • 缺點(diǎn)
    • 無法做到一對(duì)一的傳遞方式:監(jiān)聽中需要做很多消息的識(shí)別俭茧,由于postMessage發(fā)出的消息對(duì)于同一個(gè)頁面的不同功能相當(dāng)于一個(gè)廣播的過程咆疗,該頁面的所有onmessage都會(huì)收到,所以需要做消息的判斷母债;
    • 安全性問題:三方可以通過截獲午磁,注入html或者腳本的形式監(jiān)聽到消息尝抖,從而能夠做到篡改的效果,所以在postMessage和onmessage中一定要做好這方面的限制迅皇;
    • 發(fā)送的數(shù)據(jù)會(huì)通過結(jié)構(gòu)化克隆算法進(jìn)行序列化昧辽,所以只有滿足該算法要求的參數(shù)才能夠被解析,否則會(huì)報(bào)錯(cuò)登颓,如function就不能當(dāng)作參數(shù)進(jìn)行傳遞搅荞;
  • 使用方式:下面是前段時(shí)間寫的一個(gè)通信的函數(shù),sendMessage_負(fù)責(zé)發(fā)送消息框咙,bindEvent_負(fù)責(zé)消息的監(jiān)聽并處理咕痛,可以通過代碼來做一個(gè)大致了解;
Storage.prototype.sendMessage_ = function(type, params, fn) {
    if (this.topWindow) {
        this.handleCookie_(type, params, fn);
        return;
    }
    var eventId = this.addToQueue_(fn, type);
    var storageIframe = document.getElementById('mip-storage-iframe');
    var element = document.createElement("a");
    element.href = this.origin;
    var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1);     

    storageIframe.contentWindow.postMessage({
        type: type,
        params: params,
        eventId: eventId
    }, origin);
}

Storage.prototype.bindEvent_ = function() {
    window.onmessage = function (res) {
        // 判斷消息來源           
        if (window == res.source.window.parent &&
            res.data.type === this.messageType.RES &&
            window.location.href.match(res.origin.host).length > 0) {               
            var fn = this.eventQueue[res.data.eventId];
            fn && fn();
            delete this.eventQueue[res.data.eventId];
            // reset id
            var isEmpty = true;
            for (var t in this.eventQueue) {
                isEmpty = false;
            }
            if (isEmpty) {                  
                this.id = 0;
            }
        }                   
    }.bind(this);
}

cors

  • 關(guān)鍵點(diǎn):cors是一種通過前后端http header配置來進(jìn)行跨域的一種方式喇嘱;
  • 兼容性:如果不考慮pc端的IE茉贡,移動(dòng)端的opera的話那兼容性還是不錯(cuò)的,針對(duì)ie和opera可以做適當(dāng)?shù)慕导?jí)處理者铜;


    poseMessage兼容性
  • 安全策略
    • 請(qǐng)求
      • origin:通過http頭中的origin判斷域名是否是允許的腔丧;
      • Example-Same-origin:如果http origin不存在,最好能夠自己在請(qǐng)求頭中加入該參數(shù)來標(biāo)示是否是同源王暗,true表示請(qǐng)求來自于同域名下(同域名下請(qǐng)求不帶origin)悔据;如果該字段存在并且為true則允許請(qǐng)求接口,否則禁止俗壹;
      • Example_source_origin:該參數(shù)同origin科汗,是在origin不存在的情況下用來標(biāo)示請(qǐng)求來源的url
    • 返回
      • Access-Control-Allow-Origin: origin绷雏,origin表示允許哪些網(wǎng)站請(qǐng)求头滔,不建議設(shè)置為*;
      • Access-Control-Expose-Headers:Example-Access-Control-Allow-Source-Origin涎显,允許http返回中包含該字段坤检,可以通過這種方式在返回頭中加入自定義字段,如該例子中的Example-Access-Control-Allow-Source-Origin;
  • 優(yōu)點(diǎn)
    • 前端方便不少期吓,只需要發(fā)請(qǐng)求而不用考慮跨域問題早歇;
    • 安全性能夠得以控制和保障;
  • 缺點(diǎn)
    • 兼容性不全面讨勤,需要做降級(jí)處理箭跳;
  • 使用方式
    • 正常請(qǐng)求即可,無論是你要用xhr潭千,還是用一些封裝好的組件谱姓,如fetchfetchJsonp刨晴,亦或是jquery一類的技術(shù)均可屉来;
    • 后端在response時(shí)需要設(shè)置一定的配置參數(shù)路翻,并保證安全策略,具體方案可以參照下面安全策略模塊茄靠;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末茂契,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慨绳,更是在濱河造成了極大的恐慌账嚎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儡蔓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡疼邀,警方通過查閱死者的電腦和手機(jī)喂江,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旁振,“玉大人获询,你說我怎么就攤上這事」胀啵” “怎么了吉嚣?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹬铺。 經(jīng)常有香客問我尝哆,道長,這世上最難降的妖魔是什么甜攀? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任秋泄,我火速辦了婚禮,結(jié)果婚禮上规阀,老公的妹妹穿的比我還像新娘恒序。我一直安慰自己,他們只是感情好谁撼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布歧胁。 她就那樣靜靜地躺著,像睡著了一般厉碟。 火紅的嫁衣襯著肌膚如雪喊巍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天墨榄,我揣著相機(jī)與錄音玄糟,去河邊找鬼。 笑死袄秩,一個(gè)胖子當(dāng)著我的面吹牛阵翎,可吹牛的內(nèi)容都是我干的逢并。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼郭卫,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼砍聊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贰军,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤玻蝌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后词疼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俯树,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年贰盗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了许饿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舵盈,死狀恐怖陋率,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秽晚,我是刑警寧澤瓦糟,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站赴蝇,受9級(jí)特大地震影響菩浙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扯再,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一芍耘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熄阻,春花似錦斋竞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钾军,卻和暖如春鳄袍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吏恭。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工拗小, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人樱哼。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓哀九,卻偏偏與公主長得像剿配,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阅束,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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

  • 跨域資源共享 CORS 對(duì)于web開發(fā)來講呼胚,由于瀏覽器的同源策略,我們需要經(jīng)常使用一些hack的方法去跨域獲取資源...
    默默先生Alec閱讀 589評(píng)論 0 0
  • 1. 什么是跨域息裸? 跨域一詞從字面意思看蝇更,就是跨域名嘛,但實(shí)際上跨域的范圍絕對(duì)不止那么狹隘呼盆。具體概念如下:只要協(xié)議...
    w_zhuan閱讀 515評(píng)論 0 0
  • 1. 什么是跨域年扩? 跨域一詞從字面意思看,就是跨域名嘛访圃,但實(shí)際上跨域的范圍絕對(duì)不止那么狹隘常遂。具體概念如下:只要協(xié)議...
    他在發(fā)呆閱讀 822評(píng)論 0 0
  • 我有一個(gè)親姐姐,大我兩歲挽荠。 我們姐妹倆長得并不太像,小時(shí)候?yàn)橐稽c(diǎn)食物或生活用品就可以打架平绩,而誰能想到圈匆,她現(xiàn)在竟然已...
    cora的生活手冊(cè)閱讀 208評(píng)論 0 0
  • 昨天品思微分享,傅徹師父分享了“一句話的力量”捏雌。讓我反思了和女兒之間的細(xì)節(jié)跃赚。 3月10日 下班回家,剛下車性湿,女兒就...
    乖兔媽閱讀 343評(píng)論 0 2