javascript postMessage 源 IFrame

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15329710/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:24:20  来源:igfitidea点击:

postMessage Source IFrame

javascripthtmliframecross-domainpostmessage

提问by skimberk1

I'm working on a website with cross-domain iframes that are resized to the correct height using postMessage. The only problem I'm having is identifying which iframe has which height. The way I've currently got it set up is that when one iframe sends its height to the parent, all the iframes' heights are changed.

我正在处理一个具有跨域 iframe 的网站,这些 iframe 使用 postMessage 调整到正确的高度。我遇到的唯一问题是确定哪个 iframe 具有哪个高度。我目前设置它的方式是,当一个 iframe 将其高度发送给父级时,所有 iframe 的高度都会更改。

Parent:

家长:

var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

eventer(messageEvent, function(e) {
    $('iframe').height(e.data);
}, false);

Iframe:

框架:

var updateHeight = function() {
    if(window.parent) {
        window.parent.postMessage($('.widget').outerHeight(), '*');
    }
};

Is there some way to identify which iframe sent the messageevent?

有什么方法可以识别哪个 iframe 发送了message事件?

回答by Hyman

I have found the solution from here: How to share a data between a window and a frame in JavaScript

我从这里找到了解决方案:How to share a data between a window and a frame in JavaScript

Parent:

家长:

var frames = document.getElementsByTagName('iframe');
for (var i = 0; i < frames.length; i++) {
    if (frames[i].contentWindow === event.source) {
        $(frames[i]).height(event.data); //the height sent from iframe
        break;
    }
}

回答by Julien Kronegg

Yes, you can identify the IFRAME which did the postMessage. There are different situations:

是的,您可以识别执行postMessage. 有不同的情况:

  • the source IFRAME has the same-origin URL(e.g. http://example.com/) as the Window which receives the message: the IFRAME is identified using

    myIFRAME.contentWindow == event.source

  • the source IFRAME has a same-origin but relative URL(e.g. /myApp/myPage.html) to the parent HTML page: the IFRAME is identified using

    myIFRAME.contentWindow == event.source.parent

  • the source IFRAME has a cross-origin URL(e.g. http://example.com/) different of the page which receives the message (e.g http://example.org/): the above methods do not work (the comparison is always falseand accessing properties of event.sourcelead to Access Deniederrors) and the IFRAME must be identified based on its origin domain;

    myIFRAME.src.indexOf(event.origin)==0

  • 源 IFRAMEhttp://example.com/接收消息的窗口具有同源 URL(例如):IFRAME 使用

    myIFRAME.contentWindow == event.source

  • 源 IFRAME与父 HTML 页面具有同源但相对的 URL(例如/myApp/myPage.html):IFRAME 使用标识

    myIFRAME.contentWindow == event.source.parent

  • 源 IFRAME 具有与接收消息的页面不同的跨域 URL(例如http://example.com/)(例如http://example.org/):上述方法不起作用(比较总是false和访问event.source导致Access Denied错误的属性)并且 IFRAME 必须基于识别在其原始域上;

    myIFRAME.src.indexOf(event.origin)==0

In order to manage these three different situations, I'm using the following:

为了管理这三种不同的情况,我使用了以下内容:

var sourceFrame = null; // this is the IFRAME which send the postMessage
var myFrames = document.getElementsByTagName("IFRAME");
var eventSource = event.source; // event is the event raised by the postMessage
var eventOrigin = event.origin; // origin domain, e.g. http://example.com

// detect the source for IFRAMEs with same-origin URL
for (var i=0; i<myFrames.length; i++) {
    var f = myFrames[i];
    if (f.contentWindow==eventSource || // for absolute URLs
        f.contentWindow==eventSource.parent) { // for relative URLs
        sourceFrame = f;
        break;
    }
}

// detect the source for IFRAMEs with cross-origin URL (because accessing/comparing event.source properties is not allowed for cross-origin URL)
if (sourceFrame==null) {
    for (var i=0; i<myFrames.length; i++) {
        if (myFrames[i].src.indexOf(eventOrigin)==0) {
            sourceFrame = myFrames[i];
            break;
        }
    }
}

For cross-domain URLs, note that we cannot differentiate the true source if event.originis a domain common to more than one IFRAMEs.

对于跨域 URL,请注意,如果event.origin是多个 IFRAME 共有的域,我们无法区分真正的来源。

Some people use ===instead of ==but I did not found any difference in this context, so I'm using the shortest comparator.

有些人使用===而不是,==但我没有发现在这种情况下有任何区别,所以我使用的是最短的比较器。

This implementation has been tested and works under:

此实现已经过测试并适用于:

  • MSIE 9
  • Firefox 17
  • MSIE 9
  • 火狐 17

As an alternative (suggested by Griffin), you could use a IFRAME src with an unique idenfitier (e.g. timestamp), and the IFRAME'd web application will send back the this unique identifier in the posted messages. While the IFRAME identification would be simpler, this approach requires to modify the IFRAME'd web application (which is not always possible). This also may lead to security issues (e.g. the IFRAME'd web application tries to guess the unique identifier of other IFRAMEs applications).

作为替代方案(由 Griffin 建议),您可以使用具有唯一标识符(例如时间戳)的 IFRAME src,并且 IFRAME 的 Web 应用程序将在发布的消息中发回此唯一标识符。虽然 IFRAME 标识会更简单,但这种方法需要修改 IFRAME 的 Web 应用程序(这并不总是可行的)。这也可能导致安全问题(例如 IFRAME 的 Web 应用程序试图猜测其他 IFRAME 应用程序的唯一标识符)。

回答by aha

i have an idea to solve this issue. when you create the iframe give a name/id to the iframe. .

我有一个想法来解决这个问题。创建 iframe 时,请为 iframe 指定名称/ID。.

and, in the script inside iframe send the message as object which will look like

并且,在 iframe 内的脚本中,将消息作为对象发送,看起来像

window.parent.postMessage({"height" : $('.widget').outerHeight(), "frmname" : window.name}, '*');

in the parent listener,

在父侦听器中,

eventer(messageEvent, function(e) {`enter code here`
    $(e.data.frmname).height(e.data.height);
}, false);

回答by Mitar

The following works for me cross-origin:

以下适用于我的跨域:

window.addEventListener('message', function (event) {
  if (event.data.size) {
    Array.prototype.forEach.call(document.getElementsByTagName('iframe'), function (element) {
      if (element.contentWindow === event.source) {
        element.style.height = `${event.data.size.height}px`;
      }
    });
  }
}, false);

Tested in Chromium 64 and Firefox 59.

在 Chromium 64 和 Firefox 59 中测试。

回答by server herder

If the source iframe is nested in more than one parent iframe, then you will need to recurse over the window.frames property of each iframe and compare it against the messageEvent#source property.

如果源 iframe 嵌套在多个父 iframe 中,则您需要递归遍历每个 iframe 的 window.frames 属性并将其与 messageEvent#source 属性进行比较。

For example, if the message is generated by iframe#level3 of this Dom.

例如,如果消息是由这个 Dom 的 iframe#level3 生成的。

<iframe Id=level1>
   <iframe Id=level2>
       <iframe Id=level3 />
   </iframe>
</iframe>

You should be able to find the index of the ancestor iframe in the current window using.

您应该能够使用在当前窗口中找到祖先 iframe 的索引。

FindMe = event.source
FrameIndex = find(window)
frames[FrameIndex].frameElement ==     getElByTagName(iframe)[FrameIndex] 

function find(target){
    for (i=0; I< target.frames.length; i ++)
       if(target.frames[i] == FindMe ||   find(target.frames[i]))
           return i
    return false 
}

Its important to note that

重要的是要注意

The Window.frames property is not restricted by cross domain policy

Window.frames 属性不受跨域策略限制

This technique will work regardless of how deeply nested the source iframe happens to be

无论源 iframe 的嵌套有多深,此技术都将起作用

window.frames is a collection of window objects not iframe elements.

window.frames 是一个 window 对象的集合,而不是 iframe 元素。

access to the propetties s of the memebers of the window.frames collection is resttictred by Same Origin (I.e you may not be able to access the frameElement or location properties of window.frames[i]

访问 window.frames 集合成员的属性受同源限制(即您可能无法访问 window.frames[i] 的 frameElement 或位置属性)

回答by deCastongrene

The event should also have a property "source" that can be compared to the iframes "contentWindow" property.

该事件还应该有一个属性“source”,可以与 iframes 的“contentWindow”属性进行比较。