—— 全文摘自Web前端之iframe详解_someby的博客-CSDN博客_iframe详解
实现一个页面数据编辑的功能的时候就需要使用一个iframe内联框架
iframe常用属性:
1.frameborder:是否显示边框,1(yes),0(no)
2.height:框架作为一个普通元素的高度,建议在使用css设置。
3.width:框架作为一个普通元素的宽度,建议使用css设置。
4.name:框架的名称,window.frames[name]时专用的属性。
5.scrolling:框架的是否滚动。yes,no,auto。
6.src:内框架的地址,可以是页面地址,也可以是图片的地址。
7.srcdoc:用来替代原来HTML body里面的内容。但是IE不支持。
8.sandbox:对iframe进行一些列限制,IE10+支持。
获取iframe里的内容
iframe.contentWindow,获取iframe的window对象
iframe.contentDocument,获取iframe的getElement系列对象
结合Name属性,通过window提供的iframe获取,window.frames['ifr1'].window,它返回的就是window对象。即window.frames['ifr1']===window
在iframe中获取父级内容
window.parent 获取上一级的window对象,如果还是iframe则是该iframe的window对象
window.top 获取最顶级容器的window对象,即,就是你打开页面的文档
window.self 返回自身window的引用。可以理解 window===window.self
自适应iframe之蜜汁广告
广告是与原文无关的,如果是在某个div下嵌套,会造成网页布局的紊乱,而且,这样势必需要引入额外的css和js文件,极大的降低了网页的安全性。但是使用iframe,里面的内容能够被top window完全控制,而且,主页的样式不会入侵iframe里面的样式。但是,默认情况下,iframe是不适合做展示信息的,所以我们需要对其进行decorate。
自适应iframe
默认情况下,iframe会自带滚动条,不会全屏。如果你想自适应iframe的话:第一步:去掉滚动条
<iframe src="./iframe1.html" id="iframe1" scrolling="no"> </iframe>
第二步,设置iframe的高为body的高
1. var iwindow = iframe.contentwindow;
2. var idoc = iwindow.document;
3. iframe.height = idoc.body.offsetHeight;
另外,还可以添加其他的装饰属性:
属性 | 效果 |
allowtransparency | true or false 是否允许iframe设置为透明,默认为false |
allowfullscreen | true or false 是否允许iframe全屏,默认为false |
iframe安全性探索
防嵌套网页
因为iframe享有click的最优先权,当有人在伪造的主页进行点击的话,如果点在iframe上,则会默认是在操作iframe的页面。所以,为了防止网站被钓鱼,可以使用window.top来防止你的网页被iframe
//iframe2.html if(window != window.top) { window.top.location.href = correctURL; }
这段代码的主要用途是限定你的网页不能嵌套在任意网页内。如果你想引用同域的框架的话,可以判断域名。
if (top.location.host != window.location.host) { top.location.href = window.location.href; }
如果你网页不同域名的话,上述就会报错。
所以,这里可以使用try...catch...进行错误捕获。如果发生错误,则说明不同域,表示你的页面被盗用了。可能有些浏览器这样写是不会报错的,所以需要降级处理。
这时候再进行跳转即可。
try { top.location.hostname; // 检测是否出错 // 如果没有出错,则降级处理 if (top.location.hostname != window.location.hostname) { top.location.href = window.location.href; } } catch(e) { top.location.href = window.location.href; }
上面的代码只是在浏览器端,对iframe页面的权限做出相关的设置,我们还可以在服务器上,对使用iframe的权限进行设置。
以后网页安全防护的主流是Content Security Policy,他可以对iframe进行限制
CSP之页面防护
需要在服务器端设置好相关的Header。CSP的作用,他能极大的防止你的页面被XSS攻击,而且可以制定js,css,img等相关资源的origin,防止被恶意注入。不过他目前只支持Edge12+以及IE10+。
在前端,我们可以观察Response Header里是否有这样的一个Header:
Content-Security-Policy:default-src 'self' // 默认资源路径就是同域的
这就表明,你的网页时启用CSP的。
这里和iframe有一点瓜葛的时child-src和sandbox。
children-src就是用来指定iframe的有效加载路径;而,sandbox其实就和iframe的sandbox一样他可以规定来源能够带有什么权限。
来个demo:
Content-Security-Policy:child-src 'selt' http://example.com; sandbox allow-forms allow-same-originn
此时,iframe的src就只能加载同域和example.com页面。使用CSP能够很好的防止XSS攻击,原理就是CSP会默认escape掉内联样式和脚本,以及eval执行。但是,你可以使用srcipt-src进行降低限制。
Content-Security-Policy:script-src 'unsafe-inline'
当我们iframe别人的页面时,我们需要对其进行安全设限。
sandbox
sandbox就是用来给指定iframe设置一个沙盒模型限制iframe的更多权限,
sandbox时h5的一个新属性,IE10+支持,
启用方式就是使用sandbox属性:
<iframe sandbox src="..."> </iframe>
这样会对iframe页面进行一系列的限制:
1. script脚本不能执行
2. 不能发送ajax请求
3. 不能使用本地存储,即localStorage,cookie等
4. 不能创建新的弹窗和window
5. 不能发送表单
6. 不能加载额外插件比如flash等
上面的限制有点过分了 ,不过,你可以放宽一点权限。在sandbox里面进行一些简单设置
<iframe sandbox="allow-same-origin" src="...."> </iframe>
常用的配置项有:
配置 | 效果 |
allow-forms | 允许进行提交表单 |
allow-scripts | 运行执行脚本 |
allow-same-origin | 允许同域请求,比如Ajax,storage |
allow-top-navigation | 允许iframe能够主导window.top进行页面跳转 |
allow-popups | 允许iframe中弹出新窗口,比如,window.open,target="_blank" |
allow-pointer-lock | 在iframe中可以锁定鼠标,主要和鼠标锁定有关 |
可以通过在sandbox里,添加允许进行的权限。
<iframe sandbox="allow-forms allow-same-origin allow-scripts" src="..."> </iframe>
这样,就可以保证js脚本的执行,但是禁止iframe里的javascript执行top.location = self.location。
但是,iframe的安全问题还时有很多的,比如location劫持,Refers检查。
解决iframe跨域
iframe就是一个隔离沙盒,相当于我们在一个页面内可以操控很多标签页一样。
我们需要明确什么是跨域。
浏览器判断你跨没跨域,主要根据两个点。一个是你网页的协议(protocol),一个就是你的host是否相同,即,就是url的首部:
window.location.protocol + window.location.host
需要强调的是,url首部必须一样,比如:二级域名或者IP地址不一样,都算是跨域。
// 域名和域名对应ip,跨域
http://www.a.com/a.js
http://70.32.92.74/b.js
// 统一域名,不同二级域名。跨域
http://www.a.com/a.js
http://a.com/b.js
对于第二种方式的跨域(主域相同而子域不同),可以使用iframe进行解决。
在两个不同子域下(某一方使用iframe嵌套在另一方),
即:
http://www.foo.com/a.html和http://script.foo.com/b.html
两个文件中分别加上document.domain = 'foo.com',指定相同的主域,然后,两个文档就可以进行交互。
//b.html是以iframe的形式嵌套在a.html中 //www.foo.com上的a.html document.domain = 'foo.com'; var ifr = document.createElement('iframe'); ifr.src = 'http://script.foo.com/b.html'; ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; // 在这里操纵b.html alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue); }; //script.foo.com上的b.html
默认情况下document.domain是指window.location.hostname.你可以手动更改,但是最多只能设置为主域名。通常,主域名就是不带www的hostname,比如:foo.com, baidu.com。如果,带上www或者其他的前缀,就是二级域名或者多级域名。通过上述设置,相同的domain之后,就可以进行同域的相关操作。另外还可以使用iframe和location.hash,但这个技术out了。
H5的CDM跨域与iframe
如果你设置的iframe的域名和你top window的域名完全不同。则可以使用CDM(cross document messaging)进行跨域消息的传递。该API的兼容性较好 IE8+都支持。
推送消息:使用postmessage方法
接受消息:监听message事件
postmessage
该方法挂载到window对象上,即,使用window.postmessage()调用。
该方法接受两个参数:postMessage(message,targetOrigin):
message:就是传递给iframe的内容,通常是string,如果你想传object对象也可以。不过使用前请参考这一句话:
Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.
意思就是,希望亲爱的不要直接传Object。如果有条件,可以使用JSON.stringify进行转化。这样保证不会出bug。
targetOrigin:接收你传递消息的域名,可以设置绝对路径,也可以设置"" 或者 "/"。 表示任意域名都行, "/" 表示只能传递同域域名。
来个栗子:
<iframe src="http://tuhao.com" name="sendMessage"></iframe>
//当前脚本
let ifr = window.frames['sendMessage'];
//使用iframe的window向iframe发送message。
ifr.postmessage('give u a message', "http://tuhao.com");
//tuhao.com的脚本
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://tuhao.com') {
if (e.data == 'give u a message') {
e.source.postMessage('received', e.origin); //向原网页返回信息
} else {
alert(e.data);
}
}
当targetOrigin接受到message消息之后,会触发message事件。message提供的event对象上有3个重要的属性,data,origin,source.
data: postMessage传递进来的值
origin:发送消息的文档所在的域
source:发送消息文档的window对象的代理,如果是来自同一个域,则该对象就是
window,可以使用其所有方法,如果是不同的域,则window只能调用postMessage()方法返
回信息。
iframe的使用
1.通过iframe实现跨域(就是嵌入其他页面的)
2.通过iframe解决Ajax的前进后退问题
3.通过iframe实现上传
(Easyui中form组件就是用的iframe,实现表单提交,可以提交上传)
4.对低版本html不支持 iframe 元素的。
(我们可以把需要的文本放置在 <iframe> 和 </iframe> 之间,这样就可以应对浏览器了。)
<iframe width=420 height=330 frameborder=0 scrolling=auto src="URL"> </iframe>
摘录感悟
因为在工作中接手之前写的代码,里面操纵数据是使用iframe,之前只听说过,没有遇到过。今天摘抄完也是稍有理解,摘抄的目的其一是了解和学习iframe,其二是学习优秀的程序员的代码思路,知识拆解。希望自己也慢慢养成良好的习惯,不断学习总结,变得越来越厉害