跨域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 的问题的影响。
【讨论】:
你说得对,非常感谢。只需在<iframe>
中获取window.name
即可返回预期的名称。就像我在去年的回答中所说的那样,我试图在eventListener
中获取id
或name
,但这仍然不起作用。无论如何,最好只使用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 加载远程内容?我可以设置<iframe src="http://www.example.com">
来获取要显示的内容。要回答这个问题,必须使用postMessage
。问题不是要显示一个页面,而是要监听来自<iframe>
的事件并识别在父文档中触发事件的<iframe>
。干杯。
一点补充:我明白你想用 ajax 方法去哪里。但即使这应该可行(我想CORS
有很多麻烦),只要您在<iframe>
内导航,<iframe>
的内容就会被覆盖。【参考方案3】:
就像在这个帖子中看到的那样:postMessage Source IFrame 可以像这样比较每个 iframe contentWindow
和 event.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的主要内容,如果未能解决你的问题,请参考以下文章