跨域postMessage,识别iFrame

Posted

技术标签:

【中文标题】跨域postMessage,识别iFrame【英文标题】:Cross domain postMessage, identify iFrame 【发布时间】:2014-07-01 00:27:35 【问题描述】:

我使用postMessage 将事件从 iframe 发送到它的父文档。我可以控制双方,但内容来自两个不同的域。

我的简单问题是,我无法在其父回调方法中识别 iFrame。实现如下所示:

在 iFrame 中:

parent.postMessage(JSON.stringify(action: "closeView" ),'*');

在父窗口中:

window.addEventListener('message',function(event) 
if(event.origin !== 'https://example.com')
    return;

    // Parse message back to json
    var messageObject = JSON.parse(event.data);
    var source = event.source;
    /* this is returning: Window -URL- */
    console.log( source );
    /* This will throw Permission denied, although this code is inside of "parent" */
    console.log(source.parentNode);
,false);

我想识别 iframe 的某个父元素,它(逻辑上)在父文档内部。

当我尝试在所述对象上使用event.source.parentNode 或一些 jQuery 时,Firefox 说,我不能这样做来防止 XSS,错误:Error: Permission denied to access property 'parentNode'

如何获取触发 postMessage 事件监听器的 iFrame 的父元素?

【问题讨论】:

【参考方案1】:

您可以为此使用窗口名称,因为它们从 iframe 标记传递到 iframe 上下文。

父文档:

<iframe name=fr2 src="data:text/html,%3Chtml%3E%0A%20%3Cscript%3E%20parent.postMessage%28%7Bname%3A%20window.name%7D%2C%20%22*%22%29%3B%3C/script%3E%0A%3C/html%3E"></iframe>
<iframe name=fr3 src="data:text/html,%3Chtml%3E%0A%20%3Cscript%3E%20parent.postMessage%28%7Bname%3A%20name%7D%2C%20%22*%22%29%3B%3C/script%3E%0A%3C/html%3E"></iframe>

<script>onmessage = function(e) // use real event handlers in production
       alert("from frame: " + e.data.name);
 ;</script>

iframe 文档:

<html>
 <script> parent.postMessage(name: name, "*");</script>
</html>

警报“fr2”,然后是“fr3”。 然后,您可以使用属性 CSS 选择器轻松地使用 name 属性在父 DOM 中查找 iframe。

window.name+iframe 概念的说明性演示:http://pagedemos.com/namingframes/

这种极其简单的方法也不受来自相同网址 iframe 的问题的影响。

【讨论】:

你说得对,非常感谢。只需在&lt;iframe&gt; 中获取window.name 即可返回预期的名称。就像我在去年的回答中所说的那样,我试图在eventListener 中获取idname,但这仍然不起作用。无论如何,最好只使用name 属性并像您一样使用postMessage 发送它。这显然比依赖 url 更好。当@Călin Darie 的赏金到期时,我会检查这个作为答案。也许这个用户也想添加。再次感谢。 这是一种非常直接的方法。您甚至可以使用唯一键在服务器上自动生成名称 - 这样您甚至不必担心跨窗口/标签污染。【参考方案2】:

据我了解,这可以尝试 这里假设你的主窗口的 url 是 www.abc.com\home.php

  <body>
         <iframe src="www.abc.com\getOtherDomainContent.php?otherUrl=www.xyz.com"/>
    </body>

此文件中的getOtherDomainContent.php需要编写ajax调用来获取跨url内容并将该内容推送到当前iframe窗口(getOtherDomainContent.php)的正文部分。

getOtherDomainContent.php 代码:

    <html>
         <head>
//import jqry lib or other you use.
          <script>
              $(document).ready(
               //getcontent of xyz.com
                var otherUrlContent=getAjaxHtml("www.xyz.com");
                 $("body").html(otherUrlContent);
                  // further  code after content pushed.
                  //you can easily access "parent.document" and else using parent which will give you all thing you want to do with your main window
                );
          </script>
         </head>
    </html>

【讨论】:

感谢您的努力,但这个答案并没有真正解决实际问题。为什么我首先要通过 ajax 加载远程内容?我可以设置&lt;iframe src="http://www.example.com"&gt; 来获取要显示的内容。要回答这个问题,必须使用postMessage。问题不是要显示一个页面,而是要监听来自&lt;iframe&gt; 的事件并识别在父文档中触发事件的&lt;iframe&gt;。干杯。 一点补充:我明白你想用 ajax 方法去哪里。但即使这应该可行(我想CORS 有很多麻烦),只要您在&lt;iframe&gt; 内导航,&lt;iframe&gt; 的内容就会被覆盖。【参考方案3】:

就像在这个帖子中看到的那样:postMessage Source IFrame 可以像这样比较每个 iframe contentWindowevent.source

/*each(iframe...) */
frames[i].contentWindow === event.source

但我不太喜欢这个。我现在的解决方案如下所示:

在 iFrame 中:

parent.postMessage(JSON.stringify(action: "closeView", viewUrl: document.URL),'*');

更新: docuent.URL 可能会成为问题,当您使用带有位置 (#anchor) 的查询或链接时,因为您当前的 url 将与 iframe 源中的一个不同。所以不要使用document.URL,最好使用[location.protocol, '//', location.host, location.pathname].join('') (Is there any method to get the URL without query string?)

在父文档中:

window.addEventListener('message',function(event) 

    if(event.origin !== 'https://example.com')
        return;

    // Parse message back to json
    var messageObject = JSON.parse(event.data);
    // Get event triggering iFrame
    var triggerFrame = $('iframe[src="'+messageObject.viewUrl+'"]');

 ,false);

每个事件都必须将当前 iFrame URL 发送到父文档。我们现在可以使用给定的 URL 扫描文档以查找 iFrame 并使用它。

如果你们中的一些人知道更好的方法,请发布您的答案。

【讨论】:

以上是关于跨域postMessage,识别iFrame的主要内容,如果未能解决你的问题,请参考以下文章

跨域通信--Window.postMessage()

使用 iframe + postMessage 实现跨域通信

postMessage处理iframe 跨域问题

postMessage处理iframe 跨域问题

PostMessager来对子父窗体进行跨域

H5之postMessage