zoukankan      html  css  js  c++  java
  • iframe内嵌及跨域通信(iframe跨域 内嵌网页 iframe刷新重载 postMessage 事件监听)

    iframe内嵌及跨域通信

    iframe跨域 内嵌网页 iframe刷新重载 postMessage 事件监听

    前言

    对于iframe标签,现在都应该用的很少了因为它存在一些问题,比如安全问题或者能耗高,但最近笔者就使用了它做网页内嵌并跨域处理了数据,所以记录记录。

    iframe基本概念

    <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]被调用

    scrolling iframe滚动模式

    sandbox html5新特性,用于限制iframe的功能

    使用iframe的正确姿势

    可以通过以下 选择器来获取iframe节点(window.frames['xxx']的方式好像已经不能用了):

     1 document.getElementById('iframeId')
     2 
     3 document.getElementsByName('iframeName')
     4 
     5 document.getElementsByClassName('iframeClassName')
     6 
     7 document.getElementsByTagName('iframe')
     8 
     9 document.querySelector('#iframeId')
    10 
    11 document.querySelector('.iframeClassName')

    我们可以通过contentWindow和contentDocument两个API获取iframe的window对象和document对象。

    1 let iwindow = iframe.contentWindow; // 获取iframe的window对象
    2 
    3 let idoc = iframe.contentDocument; // 获取iframe的document对象

    iframe使用父级内容的正确姿势

    我们通过window.self,window.parent,window.top这三个属性分别获取自身window对象,父级window对象,顶级window对象。

    看图说话

      

    所以:

    iframe1.self === iframe1

    iframe1.parent === iframe2

    iframe2.parent === window

    iframe1.top === window

    同域/跨域

    什么是同域什么跨域咧?同域跨域的区别在哪咧?我们一般会使用iframe来进行父子页面的通信,但父子页面是否同域决定了它们之间能否进行通信。

    js遵循同源策略,即协议域名端口一致,否则都算跨域。

    同源策略 是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略。实际上,这种策略只是一个规范,并不是强制要求,各大厂商的浏览器只是针对同源策略的一种实现。它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

    跨域 简单的来说,指的是两个资源非同源。出于安全方面的考虑,页面中的JavaScript在请求非同源的资源时就会出 跨域问题 ——即跨域请求,这时,由于同源策略,我们的请求会被浏览器禁止。也就出现了 我们常说的 跨域 问题。

    通过这个图可以进一步帮助我们理解同域和跨域。

     

    iframe跨域通讯之document.domain

    对于主域相同子域不同的两个页面,我们可以通过document.domain + iframe来解决跨域通信问题。

    举个,网页a(http://www.easonwong.com)和网页b(http://script.easonwong.com),两者都设置document.domain = 'easonwong.com'(这样浏览器就会认为它们处于同一个域下),然后网页a再创建iframe上网页b,就可以进行通信啦!

    网页a

     1 document.domain = 'easonwong.com';
     2 
     3 var ifr = document.createElement('iframe');
     4 
     5 ifr.src = 'http://script.easonwong.com';
     6 
     7 ifr.style.display = 'none';
     8 
     9 document.body.appendChild(ifr);
    10 
    11 ifr.onload = function(){
    12 
    13     let doc = ifr.contentDocument || ifr.contentWindow.document;
    14 
    15     // 在这里操纵b.html
    16 
    17 };
    18 
    19  

    网页b

    document.domain = 'easonwong.com';

    iframe跨域通讯之postMessage

    postMessage是html5的新特性,具体介绍看传送门。

    postMessage介绍

    兼容性 IE8以上

    我们可以通过html5这个新特性进行iframe间的跨域通信,使用postMessage进行数据传递,通过Message监听通信事件。举个

    网页a

     1 document.domain = 'easonwong.com';
     2 
     3 var ifr = document.createElement('iframe');
     4 
     5 ifr.src = 'http://script.easonwong.com';
     6 
     7 ifr.style.display = 'none';
     8 
     9 document.body.appendChild(ifr);
    10 
    11 // 发送数据
    12 
    13 ifr.postmessage('hello, I`m a', 'http://script.easonwong.com');

    网页b

     1 // 监听message事件
     2 
     3 window.addEventListener('message', receiver, false);
     4 
     5 function receiver(e) {
     6 
     7     if (e.origin == 'http://www.easonwong.com') {
     8 
     9         if (e.data == 'hello, I`m a') {
    10 
    11             e.source.postMessage('hello, I`m b', e.origin);信息
    12 
    13         }
    14 
    15     }
    16 
    17 }

    iframe的安全问题

    iframe小广告

    很让我们讨厌iframe的一点,就是很多网站都会有各种让人防不胜防的小广告,它们大多就是用通过iframe实现的,本来想点击某个播放按钮,结果直接跳到不知道去了哪个新世界去了。

    所以我们一定要注意在用iframe的同时,要防止我们被iframe了。

    防嵌套页面操作

    在前端领域,我们可以通过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;

    }

    而后端也可以做对应的防范措施,通过设置X-Frame-Options响应头来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

    CSP

    内容安全策略(CSP)用于检测和减轻用于 Web 站点的特定类型的攻击,例如 XSS 和数据注入等。

    MDN CSP

    通过CSP配置sandbox和child-src可以设置iframe的有效地址,它限制适iframe的行为,包括阻止弹出窗口,防止插件和脚本的执行,而且可以执行一个同源策略。

    用法

    我们可以在html头部中加上<meta>标签

    <meta http-equiv="Content-Security-Policy" content="child-src 'unsafe-inline' 'unsafe-eval' www.easonwong.com">

    或者通过HTTP头部信息加上Content-Security-Policy字段

    现在回头来看看业务上的使用:

    逻辑上简单来说就是,用一个iframe标签从a网页跳到另一个b网页,并且在b页面上操作后将数据拿回a网页,效果代码如下:

    HTML:

     1 <el-dialog title="选址"
     2 
     3       width = "70%"
     4 
     5       height = '500px'
     6 
     7       :visible.sync="addrSelectDialogVisible"
     8 
     9       :before-close="handleCloseAddrSelectDialog"
    10 
    11       :modal-append-to-body="false">
    12 
    13       <div class="addr-select-box">
    14 
    15         <!-- start of 详情-->
    16 
    17         <iframe
    18 
    19         src="http://134.96.249.135:8088/ass/webLogin.do?areaCode=571" frameborder="0" width="100%" height="100%" ref="iframeId">
    20 
    21         </iframe>
    22 
    23         <!-- end of 详情-->
    24 
    25         </div>
    26 
    27     </el-dialog>
     1 //注册监听选址的消息
     2 
     3       registerSelectAddrMessage( ){
     4 
     5         let self = this ;
     6 
     7         if (navigator.appName=="Microsoft Internet Explorer"&&(navigator.appVersion.match(/8./i)=="8."||navigator.userAgent.indexOf("MSIE 8.0")>0||navigator.appVersion.match(/7./i)=="7.")){
     8 
     9             window.attachEvent('onmessage',function(e){ self.handleSelectAddrMessage( e.data );});
    10 
    11         }
    12 
    13         else {
    14 
    15             window.addEventListener('message',function(e){ self.handleSelectAddrMessage( e.data );},false);
    16 
    17         }
    18 
    19       },
    20 
    21       //监听选址信息
    22 
    23       handleSelectAddrMessage( addrMessageData ){
    24 
    25         let self = this ;
    26 
    27         //转换为标准的JSON字符串
    28 
    29         let addrMsgObj = {};
    30 
    31         if( typeof addrMessageData === 'string' && addrMessageData.indexOf( 'c3Code' ) > 0 ){
    32 
    33           var reg = /({\S*?:)|(,\S*?:)/g
    34 
    35           var formatedJSONStr = addrMessageData.replace( reg , function( a , m1 , m2 ){
    36 
    37               if( m1 ){   //如果第一个分组匹配上
    38 
    39                 return '{"' + a.slice( 1 , -1 ) + '":';
    40 
    41               }
    42 
    43               else{
    44 
    45                 return ',"' + a.slice( 1 , -1 ) + '":';
    46 
    47               }  
    48 
    49           } );
    50 
    51           formatedJSONStr = formatedJSONStr.replace( /\'/g , '"' );
    52 
    53           let addrMsgObj = {};
    54 
    55           addrMsgObj = JSON.parse( formatedJSONStr );
    56 
    57           if( addrMsgObj.c3Code ){ 
    58 
    59             self.formReviewList[self.listIndex].resourceC3 = self.cityCodeMap[ addrMsgObj.c3Code ]  ;
    60 
    61             self.formReviewList[self.listIndex].resourceC4 = addrMsgObj.c4name  ;
    62 
    63             self.formReviewList[self.listIndex].resourceAddress = addrMsgObj.address ;
    64 
    65             self.formReviewList[self.listIndex].resourceAddressId = addrMsgObj.addressId ;
    66 
    67             self.formReviewList[self.listIndex].resourcePort = addrMsgObj.epon + ',' + addrMsgObj.gpon + ',' + addrMsgObj.exchName ;
    68 
    69             //关闭选址的对话框
    70 
    71             self.addrSelectDialogVisible = false ;
    72 
    73             self.listIndex = '' ;
    74 
    75           }
    76 
    77         }
    78 
    79       },
    80 
    81  
    82 
    83 created(){
    84 
    85   let self = this;
    86 
    87   self.getWorkOrderList();
    88 
    89   //监听选址的事件响应
    90 
    91   self.registerSelectAddrMessage();
    92 
    93 },

    为了每次进入时都是新的b页面,做个重载,第一种方式没行通,用了第二种。

    重载:

    if( self.$refs.iframeId ){

      // 第一种重载必须同域

      // self.$refs.iframeId.contentWindow.location.reload( true );

      // 第二种每次赋值路径,可同域可跨域

      self.$refs.iframeId.src = 'http://134.96.249.135:8088/ass/webLogin.do?areaCode=571'

    };

    效果:

     

     

    所以在代码里做了监听** ★,°:.☆( ̄▽ ̄)/$:.°★ **。

    再举个小栗子

    father.html通过iframe包含了son.html

    father.html

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="utf-8" />
     5          <script type="text/javascript">
     6         function say(){
     7             alert("这是father的say()");
     8         }
     9         function callChild(){
    10             myFrame.window.say();
    11             myFrame.window.document.getElementById("button").value="调用结束"
    12         }
    13     </script>
    14     </head>
    15     <body>
    16          <input id="button" type="button" value="调用son.html中的函数say()" onclick="callChild()"/>
    17     <iframe name="myFrame" src="son.html"></iframe>
    18     </body>
    19 </html>

    son.html

     1 <html>
     2     <head>
     3         <meta charset="utf-8" />
     4         <script type="text/javascript">
     5             function say() {
     6                 alert("这是son的say()");
     7             }
     8             function callParent() {
     9                 parent.say();
    10                 parent.window.document.getElementById("button").value = "调用结束";
    11             }
    12         </script>
    13     </head>
    14     <body>
    15         <input id="button" type="button" value="调用father.html中的say()函数" onclick="callParent()" />
    16     </body>
    17 </html>

    方法是如何调用的?获取子页面或父页面的window对象,在通过对象调用方法。

    父页面调用子页面方法:FrameName.window.childMethod();
    子页面调用父页面方法:parent.window.parentMethod();
     
    vue版的

     vue文件里的写法:

    iframe文件里的js的写法:

    在方法调用前,以下点必须要注意!!!
    要确保在iframe加载完成后再进行操作,如果iframe还未加载完成就开始调用里面的方法或变量,会产生错误。判断iframe是否加载完成有两种方法:
    1. iframe上用onload事件
    2. 用document.readyState=="complete"来判断
  • 相关阅读:
    vmware ubuntu 异常关机无法连接到网络
    Speed up GCC link
    常用的一些解压命令
    Log4j 漏洞复现
    Test Case Design method Boundary value analysis and Equivalence partitioning
    CCA (Citrix Certified Administrator) exam of “Implementing Citrix XenDesktop 4”
    What is Key Word driven Testing?
    SAP AGS面试小结
    腾讯2013终端实习生一面
    指针的引用
  • 原文地址:https://www.cnblogs.com/karajanking/p/14636733.html
Copyright © 2011-2022 走看看