前言
說起iframe,大家都會(huì)覺得很嫌棄或者很不愿接近,原因大概都是:能耗高,安全問題,spider不喜歡它...也有(不少)同學(xué)內(nèi)心獨(dú)白就是:不!這很low很dirty,我才不想用惹!但是我們必須的承認(rèn)iframe之強(qiáng)大,很多時(shí)候我們都會(huì)(不得不)使用它,真的素又愛又恨吶-8-
今天就在這里和大家一起好好討論一下iframe。
iframe基本概念
我們先看一個(gè)??
<iframe src="demo.html" height="300" width="500" name="demo" scrolling="auto" sandbox="allow-same-origin"></iframe>
iframe的一些基本屬性:
- src iframe頁面地址,有同域跨域之分
- height iframe高度
- width iframe寬度
- name iframe命名,可通過window.frames[xxx]被調(diào)用
- scrolling iframe滾動(dòng)模式
- sandbox html5新特性,用于限制iframe的功能
使用iframe的正確姿勢
我們可以通過contentWindow
和contentDocument
兩個(gè)API獲取iframe的window對(duì)象和document對(duì)象。
let iframe = document.getElementById('demo');
let iwindow = iframe.contentWindow; // 獲取iframe的window對(duì)象
let idoc = iframe.contentDocument; // 獲取iframe的document對(duì)象
剛剛我們提到了iframe的name屬性,我們也可以通過window.frames[iframeName]來調(diào)用iframe。
let iframe = window.frames['demo']
iframe使用父級(jí)內(nèi)容的正確姿勢
我們通過window.self
,window.parent
,window.top
這三個(gè)屬性分別獲取自身window對(duì)象,父級(jí)window對(duì)象,頂級(jí)window對(duì)象。
看圖說話
iframe1.self === iframe1
iframe1.parent === iframe2
iframe2.parent === window
iframe1.top === window
同域/跨域
什么是同域什么跨域咧?同域跨域的區(qū)別在哪咧?我們一般會(huì)使用iframe來進(jìn)行父子頁面的通信,然鵝父子頁面是否同域決定了它們之間能否進(jìn)行通信。
js遵循同源策略,即同協(xié)議,同域名,同端口號(hào),否則都算跨域。
同源策略 是由Netscape提出的一個(gè)著名的安全策略,現(xiàn)在所有支持JavaScript 的瀏覽器都會(huì)使用這個(gè)策略。實(shí)際上,這種策略只是一個(gè)規(guī)范,并不是強(qiáng)制要求,各大廠商的瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響。
跨域 簡單的來說,指的是兩個(gè)資源非同源。出于安全方面的考慮,頁面中的JavaScript在請(qǐng)求非同源的資源時(shí)就會(huì)出 跨域問題 ——即跨域請(qǐng)求,這時(shí),由于同源策略,我們的請(qǐng)求會(huì)被瀏覽器禁止。也就出現(xiàn)了 我們常說的 跨域 問題。
通過這個(gè)圖可以進(jìn)一步幫助我們理解同域和跨域。
iframe跨域通訊之document.domain
對(duì)于主域相同子域不同的兩個(gè)頁面,我們可以通過document.domain + iframe來解決跨域通信問題。
舉個(gè)??,網(wǎng)頁a(http://www.easonwong.com)和網(wǎng)頁b(http://script.easonwong.com),兩者都設(shè)置document.domain = 'easonwong.com'
(這樣瀏覽器就會(huì)認(rèn)為它們處于同一個(gè)域下),然后網(wǎng)頁a再創(chuàng)建iframe上網(wǎng)頁b,就可以進(jìn)行通信啦~!
網(wǎng)頁a
document.domain = 'easonwong.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.easonwong.com';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
let doc = ifr.contentDocument || ifr.contentWindow.document;
// 在這里操縱b.html
};
網(wǎng)頁b
document.domain = 'easonwong.com';
iframe跨域通訊之postMessage
postMessage是html5的新特性,具體介紹不在此贅述。
postMessage介紹
兼容性 IE8以上
我們可以通過html5這個(gè)新特性進(jìn)行iframe間的跨域通信,使用postMessage進(jìn)行數(shù)據(jù)傳遞,通過Message監(jiān)聽通信事件。舉個(gè)??
網(wǎng)頁a
document.domain = 'easonwong.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.easonwong.com';
ifr.style.display = 'none';
document.body.appendChild(ifr);
// 發(fā)送數(shù)據(jù)
ifr.postmessage('hello, I`m a', 'http://script.easonwong.com');
網(wǎng)頁b
// 監(jiān)聽message事件
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://www.easonwong.com') {
if (e.data == 'hello, I`m a') {
e.source.postMessage('hello, I`m b', e.origin);信息
}
}
}
iframe實(shí)現(xiàn)JSBridge
在移動(dòng)端Hybrid混合模式中經(jīng)常用到JSBridge進(jìn)行JS和Native之間的通信,其中我們可以通過iframe的方式實(shí)現(xiàn)JS調(diào)用Native的方法。
以上提到的方法就是URL SCHEME攔截。
URL SCHEME是一種類似于url的鏈接,是為了方便app直接互相調(diào)用設(shè)計(jì)的,形式和普通的 url 近似,主要區(qū)別是 protocol 和 host 一般是自定義的,例如: easonwong://hh/url?name=easonwong,其中protocol是easonwong,host則是hh。
我們通過創(chuàng)建一個(gè)iframe(src設(shè)為我們自定義的URL SCHEME)來發(fā)送請(qǐng)求,然后Native那邊可以攔截到請(qǐng)求并獲取其中帶有的參數(shù),即可進(jìn)行后續(xù)的操作。
想了解更多具體的關(guān)于JSBridge的內(nèi)容,可以閱讀我的JSBridge學(xué)習(xí)筆記~
iframe的其他用途
- 用iframe進(jìn)行異步請(qǐng)求
在很久很久很久以前,久到ajax還沒出現(xiàn)的時(shí)候,人們會(huì)用iframe來進(jìn)行異步請(qǐng)求。大概就是異步創(chuàng)建iframe,然后后臺(tái)返回?cái)?shù)據(jù)在iframe中,我們在從里面獲取數(shù)據(jù)。
例如在我做過的一個(gè)項(xiàng)目中,通過iframe.src傳入一個(gè)文件下載地址,實(shí)現(xiàn)無需打開新窗口下載文件。
引用/展示第三方內(nèi)容
需要獨(dú)立樣式和帶有交互的內(nèi)容,例如幻燈片
sandbox沙箱隔離
歷史記錄管理
iframe的安全問題
iframe小廣告
很讓我們討厭iframe的一點(diǎn),就是很多*網(wǎng)站都會(huì)有各種讓人防不勝防的小廣告,它們大多就是用通過iframe實(shí)現(xiàn)的,本來想點(diǎn)擊某個(gè)播放按鈕,結(jié)果馬鴨直接跳幾十跳不知道去了哪個(gè)新世界去了。
更討厭的一種情況是,可能不知道哪天用戶突然拿刀過來,說我們的項(xiàng)目頁面里出現(xiàn)了野雞廣告,說我們在消費(fèi)他們,一臉懵逼的我們覺得十分無辜。實(shí)際上就是我們的頁面被運(yùn)行商劫持了,被掛上了注入了不知名的野雞廣告。
所以我們一定要注意在用iframe的同時(shí),要防止我們被iframe了。
防嵌套頁面操作
在前端領(lǐng)域,我們可以通過window.top
來防止我們頁面被嵌套。
if(window != window.top){
window.top.location.href = myURL;
}
或者通過window.location.host
來檢測是否跨域了
if (top.location.host != window.location.host) {
top.location.href = window.location.href;
}
而后端也可以做對(duì)應(yīng)的防范措施,通過設(shè)置X-Frame-Options響應(yīng)頭來確保自己網(wǎng)站的內(nèi)容沒有被嵌到別人的網(wǎng)站中去,也從而避免了點(diǎn)擊劫持 (clickjacking) 的攻擊。
CSP
內(nèi)容安全策略(CSP)用于檢測和減輕用于 Web 站點(diǎn)的特定類型的攻擊,例如 XSS 和數(shù)據(jù)注入等。
通過CSP配置sandbox和child-src可以設(shè)置iframe的有效地址,它限制適iframe的行為,包括阻止彈出窗口,防止插件和腳本的執(zhí)行,而且可以執(zhí)行一個(gè)同源策略。
用法
- 我們可以在html頭部中加上
<meta>
標(biāo)簽
<meta http-equiv="Content-Security-Policy" content="child-src 'unsafe-inline' 'unsafe-eval' www.easonwong.com">
- 或者通過HTTP頭部信息加上Content-Security-Policy字段
想了解更多具體的關(guān)于CSP或者XSS攻擊等網(wǎng)絡(luò)安全內(nèi)容,可以閱讀我的網(wǎng)絡(luò)攻擊與安全防御學(xué)習(xí)筆記~