iframe 跨域問題 iframe 跨域通信 postMessage

概述

JavaScript出于安全方面的考慮两嘴,不允許跨域調(diào)用其他頁面的對象肠套。但在安全限制的同時也給注入iframe或是ajax應(yīng)用上帶來了不少麻煩栗柒。這里把涉及到跨域的一些問題簡單地整理一下:

首先什么是跨域,簡單地理解就是因為JavaScript同源策略的限制呀伙,http://a.com?域名下的js無法操作http://b.com或是http://c.a.com域名下的對象补履。更詳細的說明可以看下表:

對于主域相同子域不同的通信方法這里不一一列舉了,這里主要講解一下跨主域的通信問題区匠。

postMessage方法

window.postMessage 是一個用于安全的使用跨源通信的方法干像。通常,不同頁面上的腳本只在這種情況下被允許互相訪問驰弄,當且僅當執(zhí)行它們的頁面所處的位置使用相同的協(xié)議(通常都是 http)麻汰、相同的端口(http默認使用80端口)和相同的主機(兩個頁面的 document.domain 的值相同)。 在正確使用的情況下戚篙,window.postMessage 提供了一個受控的機制來安全地繞過這一限制五鲫。

兼容性

http://caniuse.com/#search=postMessage

具體用法

發(fā)送消息:destination.postMessage(message, targetOrigin);

destination: 目標窗口

message:發(fā)送的消息

targetOrigin: 定義發(fā)送消息的范圍

監(jiān)聽接受消息:window.addEventListener(‘message’,callback,false);

已知問題

部分版本IE8/9瀏覽器只支持iframe通信,不支持tabs之間通信岔擂。

IE8/9不能傳輸對象位喂,只能傳輸string。

參考資料

mozlia官方文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/Window.postMessage

IE官方文檔:https://status.modern.ie/postmessage

webplatform文檔:https://docs.webplatform.org/wiki/apis/web-messaging/MessagePort/postMessage

HTML5官方文檔:https://html.spec.whatwg.org/multipage/comms.html#web-messaging

window.navigator(適用于ie6/7)

ie6/7有個漏洞,父窗口與所有的iframe共享window.navigator對象乱灵,可以利用這個漏洞塑崖,由于ie6/7不支持postMessage,所以可以利用這個漏洞對ie6/7做兼容跨域通信支持。

具體用法

途中A過程和B過程都是初始化監(jiān)聽事件痛倚,類似于onmessage事件规婆。只不過實現(xiàn)方法不一樣而已。

按執(zhí)行順序來描述的話,如下:

B: 父窗口向window.navigator添加一個監(jiān)聽函數(shù)抒蚜,并打上父窗口的戳掘鄙。

A: 子窗口向window.navigator添加一個監(jiān)聽函數(shù),并打上子窗口的戳嗡髓。

C: 父窗口執(zhí)行post的時候操漠,調(diào)用原先子窗口添加在navigator里的監(jiān)聽函數(shù),并將要傳輸?shù)臄?shù)據(jù)作為函數(shù)參數(shù)傳入饿这。

D: 子窗口執(zhí)行post的時候浊伙,調(diào)用原先父窗口添加在navigator里的監(jiān)聽函數(shù),并將要傳輸?shù)臄?shù)據(jù)作為函數(shù)參數(shù)傳入蛹稍。

注意:子窗口和父窗口要找到對方的監(jiān)聽函數(shù)必須得事先知道對方在添加監(jiān)聽函數(shù)的時候打上的戳

JavaScript由于同源策略的限制,跨域通信一直是棘手的問題吧黄。當然解決方案也有很多:

document.domain+iframe的設(shè)置,應(yīng)用于主域相同而子域不同唆姐;

利用iframe和location.hash,數(shù)據(jù)直接暴露在了url中廓八,數(shù)據(jù)容量和類型都有限

Flash LocalConnection奉芦, 對象可在一個 SWF 文件中或多個 SWF 文件間進行通信, 只要在同一客戶端就行剧蹂,跨應(yīng)用程序声功, 可以跨域。

window.name 保存數(shù)據(jù)以及跨域 iframe 靜態(tài)代理動態(tài)傳輸方案宠叼,充分的運用了window.name因為頁面的url改變而name不改變的特性先巴。

各種方案網(wǎng)上都有很多實例代碼,大家可以自己搜索一下冒冬。

html5中最炫酷的API之一:就是?跨文檔消息傳輸Cross Document Messaging伸蚯。高級瀏覽器Internet Explorer 8+, chrome,F(xiàn)irefox , Opera 和 Safari 都將支持這個功能简烤。這個功能實現(xiàn)也非常簡單主要包括接受信息的”message”事件和發(fā)送消息的”postMessage”方法剂邮。

發(fā)送消息的”postMessage”方法

向外界窗口發(fā)送消息:

otherWindow.postMessage(message,targetOrigin);

otherWindow: 指目標窗口,也就是給哪個window發(fā)消息横侦,是 window.frames 屬性的成員或者由 window.open 方法創(chuàng)建的窗口

參數(shù)說明:

message: 是要發(fā)送的消息挥萌,類型為 String、Object (IE8枉侧、9 不支持)

targetOrigin: 是限定消息接收范圍引瀑,不限制請使用 ‘*’

接受信息的”message”事件

var onmessage = function (event) {

var data = event.data;

var origin = event.origin;

//do someing

};

if (typeof window.addEventListener != 'undefined') {

window.addEventListener('message', onmessage, false);

} else if (typeof window.attachEvent != 'undefined') {

//for ie

window.attachEvent('onmessage', onmessage);

}

回調(diào)函數(shù)第一個參數(shù)接收 Event 對象,有三個常用屬性:

data: 消息

origin: 消息來源地址

source: 源 DOMWindow 對象

看一個簡單的來自網(wǎng)上的demo:?http://www.css88.com/demo/postmessage/

當然postmessage也有一些不足的地方:

ie8榨馁,ie9下傳遞的數(shù)據(jù)類型值支持字符串類型憨栽,不過可以使用用?JSON對象和字符串之間的相互轉(zhuǎn)換?來解決這個問題;

ie6,ie7需要寫兼容方案徒像,個人認為window.name比較靠譜黍特;

參考網(wǎng)址:

http://js8.in/752.html

http://www.36ria.com/3890

http://www.planeart.cn/?post_type=post&p=1620

數(shù)據(jù)發(fā)送端

首先我們要做的是創(chuàng)建通信發(fā)起端,也就是數(shù)據(jù)源”source”锯蛀。作為發(fā)起端灭衷,我們可以open一個新窗口,或創(chuàng)建一個iframe旁涤,往新窗口里發(fā)送數(shù)據(jù)翔曲,簡單起見,我們每6秒鐘發(fā)送一次劈愚,然后創(chuàng)建消息監(jiān)聽器瞳遍,從目標窗口監(jiān)聽它反饋的信息。

//彈出一個新窗口 var domain = 'http://scriptandstyle.com'; var myPopup = window.open(domain + '/windowPostMessageListener.html','myWindow'); //周期性的發(fā)送消息 setInterval(function(){ var message = 'Hello! The time is: ' + (new Date().getTime()); console.log('blog.local: sending message: ' + message); //send the message and target URI myPopup.postMessage(message,domain); },6000); //監(jiān)聽消息反饋 window.addEventListener('message',function(event) { if(event.origin !== 'http://scriptandstyle.com') return; console.log('received response: ',event.data); },false);

這里我使用了window.addEventListener菌羽,但在IE里這樣是不行的掠械,因為IE使用window.attachEvent。如果你不想判斷瀏覽器的類型注祖,可以使用一些工具庫猾蒂,比如jQuery或Dojo。

假設(shè)你的窗口正常的彈出來了是晨,我們發(fā)送一條消息——需要指定URI(必要的話需要指定協(xié)議肚菠、主機、端口號等)罩缴,消息接收方必須在這個指定的URI上蚊逢。如果目標窗口被替換了,消息將不會發(fā)出箫章。

我們同時創(chuàng)建了一個事件監(jiān)聽器來接收反饋信息烙荷。有一點極其重要,你一定要驗證消息的來源的URI炉抒!只有在目標方合法的情況才你才能處理它發(fā)來的消息奢讨。

如果是使用iframe,代碼應(yīng)該這樣寫:

//捕獲iframe var domain = 'http://scriptandstyle.com'; var iframe = document.getElementById('myIFrame').contentWindow; //發(fā)送消息 setInterval(function(){ var message = 'Hello! The time is: ' + (new Date().getTime()); console.log('blog.local: sending message: ' + message); //send the message and target URI iframe.postMessage(message,domain); },6000);

確保你使用的是iframe的contentWindow屬性焰薄,而不是節(jié)點對象拿诸。

數(shù)據(jù)接收端

下面我們要開發(fā)的是數(shù)據(jù)接收端的頁面。接收方窗口里有一個事件監(jiān)聽器塞茅,監(jiān)聽“message”事件亩码,一樣,你也需要驗證消息來源方的地址野瘦。消息可以來自任何地址描沟,要確保處理的消息是來自一個可信的地址飒泻。

//響應(yīng)事件 window.addEventListener('message',function(event) { if(event.origin !== 'http://davidwalsh.name') return; console.log('message received: ' + event.data,event); event.source.postMessage('holla back youngin!',event.origin); },false);

上面的代碼片段是往消息源反饋信息,確認消息已經(jīng)收到吏廉。下面是幾個比較重要的事件屬性:

source – 消息源泞遗,消息的發(fā)送窗口/iframe。

origin – 消息源的URI(可能包含協(xié)議席覆、域名和端口)史辙,用來驗證數(shù)據(jù)源。

data – 發(fā)送方發(fā)送給接收方的數(shù)據(jù)佩伤。

這三個屬性是消息傳輸中必須用到的數(shù)據(jù)聊倔。

觀看演示

使用window.postMessage

跟其他很web技術(shù)一樣,如果你不校驗數(shù)據(jù)源的合法性生巡,那使用這種技術(shù)將會變得很危險耙蔑;你的應(yīng)用的安全需要你對它負責。window.postMessage就像是PHP相對于JavaScript技術(shù)孤荣。window.postMessage很酷甸陌,不是嗎?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垃环,一起剝皮案震驚了整個濱河市邀层,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遂庄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劲赠,死亡現(xiàn)場離奇詭異涛目,居然都是意外死亡,警方通過查閱死者的電腦和手機凛澎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門霹肝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塑煎,你說我怎么就攤上這事沫换。” “怎么了最铁?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵讯赏,是天一觀的道長。 經(jīng)常有香客問我冷尉,道長漱挎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任雀哨,我火速辦了婚禮磕谅,結(jié)果婚禮上私爷,老公的妹妹穿的比我還像新娘。我一直安慰自己膊夹,他們只是感情好衬浑,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著放刨,像睡著了一般工秩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宏榕,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天拓诸,我揣著相機與錄音,去河邊找鬼麻昼。 笑死奠支,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的抚芦。 我是一名探鬼主播倍谜,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼叉抡!你這毒婦竟也來了尔崔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤褥民,失蹤者是張志新(化名)和其女友劉穎季春,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體消返,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡载弄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撵颊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇攻。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖倡勇,靈堂內(nèi)的尸體忽然破棺而出逞刷,到底是詐尸還是另有隱情,我是刑警寧澤妻熊,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布夸浅,位于F島的核電站,受9級特大地震影響固耘,放射性物質(zhì)發(fā)生泄漏题篷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一厅目、第九天 我趴在偏房一處隱蔽的房頂上張望番枚。 院中可真熱鬧法严,春花似錦、人聲如沸葫笼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽路星。三九已至溯街,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洋丐,已是汗流浹背呈昔。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留友绝,地道東北人堤尾。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像迁客,于是被迫代替她去往敵國和親郭宝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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

  • 1. 什么是跨域掷漱? 跨域一詞從字面意思看粘室,就是跨域名嘛,但實際上跨域的范圍絕對不止那么狹隘卜范。具體概念如下:只要協(xié)議...
    w_zhuan閱讀 510評論 0 0
  • 1. 什么是跨域衔统? 跨域一詞從字面意思看,就是跨域名嘛海雪,但實際上跨域的范圍絕對不止那么狹隘缰冤。具體概念如下:只要協(xié)議...
    他在發(fā)呆閱讀 822評論 0 0
  • 跨域是什么 同源策略 在講解什么是跨域之前先要清楚什么是同源策略,“同源政策”(same-origin polic...
    JRG_Orange閱讀 953評論 0 52
  • 什么是跨域 跨域喳魏,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的怀薛,是瀏覽器對JavaScript實...
    Yaoxue9閱讀 1,286評論 0 6
  • 什么是跨域 跨域刺彩,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的枝恋,是瀏覽器對JavaScript實...
    HeroXin閱讀 831評論 0 4