• 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"来判断
  • 相关阅读:
    Java 通过SFTP上传图片功能
    Java 签名验签工具类
    winform自定义分页控件
    C# ini配置文件操作类
    c# 使用Renci.SshNet.dll操作SFTP总结
    .net core 2.0 webapi部署iis操作
    WORDPRESS修改文章文件后,出现乱码
    WP-PostViews使用
    wordpress WP-PageNavi分页
    如何让搜索引擎抓取AJAX内容?
  • 原文地址:https://www.cnblogs.com/karajanking/p/14636733.html
Copyright © 2020-2023  润新知