美文网首页
Iframe中跨域进行父子窗口进行通信

Iframe中跨域进行父子窗口进行通信

作者: 扶得一人醉如苏沐晨 | 来源:发表于2022-05-09 17:22 被阅读0次

 一、跨域简介

1. 首先简单介绍一下什么是跨域

当我们在浏览器的地址栏中输入一个地址的时候,这个地址通常包含四部分信息内容。这四部分信息包含:①协议、②域名、③端口、④资源位置。

 其中前三部分将会决定是否存在跨域,即:协议、域名、端口。如果其中有一个不一样,浏览器就会认为存在跨域的问题。例如:

    2.跨域的种类

一般有两种形式的跨域问题:

            ①使用XmlHttpRequest(XHR)或者使用AJAX发送的POST或者GET请求。这种形式的跨域是:前端页面与后端进行的跨域请求。这种形式跨域不在本篇文章的讨论范围内。 

  ②父子页面之间进行的DOM操作(父子窗口之间的document操作)。这种形式的跨域是:前端页面与前端页面之间的通信或者相互操作的形成跨域。(本文主要讨论就是这个话题)

   3.跨域的提示

 如果在页面上出现了上面任何一种形式的跨域,一般会在浏览器的控制台(Chrome中按F12键)打印下面一段类似的描述:(一般包含accessing a cross-origin类似的信息就是跨域了)





二、问题描述


1.父子页面之间的DOM操作


在HTML页面中,我们有时候会使用<iframe>标签打开一个子窗口,又或者使用window.open方法打开一个子窗口,但有时想让父子窗口之间进行通信。

①、如果<iframe>中src属性配置的地址和父窗口在同一个域下,可以在子窗口中通过window.parent.document来获取父窗口的DOM对象。亦或父窗口也可以通过contentWindow属性获取子窗口的DOM对象(Iframe情况下)。例如:document.getElementById('iframe标签的ID').contentWindow。两者之间操作不会出现任何跨域的问题,可以自由的获取任意想要的元素信息内容。也就不在本篇文章的讨论范围内。

父子页面(iframe)相互获取对方dom元素
父页面获取子页面的dom

 子页面获取父页面的dom

 ②、如果<iframe>中的src属性配置的地址与父窗口不在同一个域下,即:协议、域名、端口任何一个不一样都会造成跨域问题。当使用window.parent.document进行操作的时候,就会提示跨域的问题,就是上面截图的信息内容。又或者使用contentWindow属性也会提示相同的跨域问题。有以下几种解决问题的方法以及这些方法的局限性。

三、解决页面之间跨域问题的方法

使用postMessage方式


 在HTML页面中,可以在当前页面中使用window.parent获取父级窗口对象(WIndow),从而向父级窗口发送消息(子->父)。同样也可以使用contentWindow获取Iframe的打开的子窗口对象,从而向子窗口发送消息。(父->子

如果两个父子窗口存在跨域问题,那么将不能对获取到的window对象进行任何操作。如果进行了任何的操作,都会提示跨域的问题。但是有两个是例外。即使在跨域的情况下也可以对其进行设置。

location属性:设置window准备跳转的页面

postMessage方法,H5之后添加的。

即使这两个域名之间存在跨域问题,在window对象中有一个属性location的设置和一个方法postMessage的调用不会受到跨域的影响。

postMessage和addEventListener方法配合使用。postMessage是用来发送消息的,addEventListener是用来接收消息时候的回调。最后需要用removeEventListener在destory生命周期销毁监听。

①发送的消息:可以是字符串,也可以是对象。

②接收消息的域名:要么是具体值(协议、域名、端口都要设置,且相同),要么是*。如果设置为*:则表示没有任何限制。如果设置为具体值的话,则必须与发送到的窗口域名相同,包含协议、域名、端口,如果有一个不同的话,就会发送不出去。

 例如:parent.window.postMessage('父窗口你好','http://father.moxiao.com'),就会提示错误。因为parent.window窗口的域名为:http://father.moxiao.com:8082,而发送配置的域名是:http://father.moxiao.com。就会提示下面的错误信息:


   例如:                

parent.window.postMessage(content,'http://father.moxiao.com:8081');

addEventListener方法有两个参数:

     ①监听的时间类型:对于发送消息而言,固定为message。

    ②回调函数:在回调函数中一个参数event,event其中包含三个重要的属性:

  1.data:表示接受到的消息内容,可能是字符串,可能是对象,取决有发送方。

  2.origin:String类型,表示发送消息的域名地址

  3.source:对象,表示发送消息的窗口对象。


除此之外还有其他跨域通信方式

使用window.name属性

       window.name用于表示当前窗口的名称。可以容纳2M的大小内容。注意:在跨域的情况下,不能设置window.name的属性值,也不能获取其中的属性值。一般window.name属性要配合window.location属性进行操作。

window.name属性进行消息传递的原理

        window.name表示当前窗口的名称。一个窗口在没有关闭之前,可以在地址栏中进行多次地址改变。但是他们都共享同一个window.name属性值。即只要当前窗口不关闭,无论进行多少次地址跳转,这些地址是否存在跨域都没有关系,window.name将保存最后一次窗口的设置的值。

      你也可以自行体验一把:打开Chrome的控制台,当前地址为:www.baidu.com。你在console的控制台中输入window.name='moxiao',然后将当前页面的地址栏的地址改为:mai.qq.com,然后在console的控制台中打印window.name将会显示:‘moxiao’。

        window.name的值可以在多个跨域地址中持久化,这也就是跨域父子窗口可以进行消息传递的基石。但是window.name属性的设置和获取是不能跨域进行操作的。如果父窗口想设置子窗口的window.name的属性值,必须在同一个域下。父窗口向获取子窗口的window.name的属性值,也必须在同一个域名下。

        当知道window.name属性可以在多个页面之间进行持久化的这个机制后,我们就会想象一下如何进行跨域的父子窗口传递消息。

         当父窗口想向子窗口传递消息时:我们在父窗口的项目中添加一个代理页面(proxy.html),因为父窗口和代理页面在同一个项目下,所以不存在跨域的问题,这时候就可以在父窗口对代理窗口的window.name设置要传递的消息内容,设置完成之后,让代理页面进行window.location跳转到子窗口中,因为是同一个窗口,所以window.name属性将会持久化到子窗口中。这样就可以在子窗口获取当前窗口的window.name属性值,也就是父窗口想要传递的消息。


使用hashtag的方式

 hashtag介绍以及原理

        hashtag是地址栏中#之后的部分。注意:hash是地址栏的最后一部分。地址栏中传递的参数必须在#之前,否则会将他们当成是hashtag的一部分,而不是传递的参数了。

        hashtag的一个显著的特征就是:hashtag的改变不会对页面进行重新加载。即不会发送一个HTTP请求。当我们在地址栏中输入一个地址时,会向服务器发送HTTP请求。当改变地址栏传递的参数时(?后面的参数),会重新发送HTTP请求。但是设置或者改变hashtag不会重新发送HTTP请求。给人直观的印象就是地址栏中的地址改变了,然后就没有任何其他的操作了。

         可以使用window.location.hash的方式获取。注意:获取到的hash值是包含#号的。

相关文章

网友评论

      本文标题:Iframe中跨域进行父子窗口进行通信

      本文链接:https://www.haomeiwen.com/subject/phaxurtx.html