如何在 JavaScript 中的窗口和框架之间共享数据

发布于 2024-12-21 08:45:22 字数 1147 浏览 2 评论 0原文

这是特定于 WebKit 浏览器的(意味着我只需要使其在特定于 WebKit 的浏览器(即 iOS/Android 浏览器)中工作,但我正在 Chrome 中进行测试)。

我有一个页面。该页面加载一个或多个 iframe,其中包含来自另一域的内容。我需要从这些 iframe 接收消息(使用 postMessage()),并且我需要能够识别特定消息来自哪个 iframe。

我找不到一种不涉及抛出 iframe URL 的方法,然后 iframe 内容可以将其传回给我。我不想干预 URL,因为不能保证我可以安全地做到这一点(例如,重定向可能会抛出参数)。

我尝试了一些我认为合理的事情。当我创建 iframe 元素(由 J/S 完成)时,我将一个属性与该元素关联起来,假设为“shared_secret”。当我从框架返回消息事件时,我尝试找到创建调用框架所使用的元素,并读取该属性。

function onMessage(evt) {
  var callerId = evt.source.frameElement.shared_secret;
  // ....
}

window.addEventListener(message, onMessage);

var frameEl = document.createElement('iframe');
frameEl.shared_secret = 'sommething blue';
frameEl.src = 'http://aliens.com/my.html';
somewhereInMyDoc.appendChild(frameEl);

当框架加载时,它将运行:

window.parent.postMessage('do you know who I am?', '*');

但是,在上面的 onMessage() 中,frameElement 结果未定义。我想出于安全原因,当父/子来自同一域时它确实可以完美工作。

这实际上很讽刺。父窗口无法访问 event.source.frameElement,因为 event.source 是外来窗口。 iFrame 窗口不能调用window.frameElement,因为frameElement 位于外来窗口中。所以没有人可以访问它。

那么,有什么东西可以用作我可以在新加载的框架上设置的令牌,并以某种方式取回吗?

谢谢。

This is WebKit browsers specific (meaning that I only need to make it work in WebKit specific, i.e. iOS/Android browsers, but I'm testing in Chrome).

I have a page. The page loads one or more iframes, with contents from another domain. I need to receive messages (using postMessage()) from these iframes, and I need to be able to identify which iframe a specific message came from.

I can't find a way to do that that does not involve throwing something the iframe URL that the iframe contents then can pass back to me. I would like to not have to meddle with the URL, as there is no guarantee I can safely do that (redirects can throw the parameters out, for example).

I tried something that I thought was reasonable. When I create the iframe element (it's done from J/S), I associated a property with the element, let's say 'shared_secret'. When I get the message event back from the frame, I tried to locating the element that the calling frame was created with, and reading that property.

function onMessage(evt) {
  var callerId = evt.source.frameElement.shared_secret;
  // ....
}

window.addEventListener(message, onMessage);

var frameEl = document.createElement('iframe');
frameEl.shared_secret = 'sommething blue';
frameEl.src = 'http://aliens.com/my.html';
somewhereInMyDoc.appendChild(frameEl);

When the frame loads, it will run:

window.parent.postMessage('do you know who I am?', '*');

However, frameElement turns out undefined in the above onMessage(). I guess for the security reasons, it does work perfectly when the parent/child are from the same domain.

And it's actually ironic. Parent window can not access event.source.frameElement because event.source is an alien window. iFrame window can not call window.frameElement, because frameElement is in an alien window. So nobody can get access to it.

So, is there something that I can use as a token that I can set on a newly loaded frame, and somehow get back?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瀞厅☆埖开 2024-12-28 08:45:22

对于寻找代码的人,这里是我用来查找发送消息的 iframe 的方法:

/**
 * Returns the iframe corresponding to a message event or null if not found.
 * 
 * 'e' is the event object
 */
function getFrameTarget (e) {
    var frames = document.getElementsByTagName('iframe'),
        frameId = 0,
        framesLength = frames.length;

    for (; frameId < framesLength; frameId++) {
        if (frames[frameId].contentWindow === e.source) {
            return frames[frameId];
        }
    }

    return null;
}

感谢 Pawel Veselov 和 DMoses!

For people looking for some code, here is what I used to find the iframe who sent the message :

/**
 * Returns the iframe corresponding to a message event or null if not found.
 * 
 * 'e' is the event object
 */
function getFrameTarget (e) {
    var frames = document.getElementsByTagName('iframe'),
        frameId = 0,
        framesLength = frames.length;

    for (; frameId < framesLength; frameId++) {
        if (frames[frameId].contentWindow === e.source) {
            return frames[frameId];
        }
    }

    return null;
}

Thanks to Pawel Veselov and DMoses !

記柔刀 2024-12-28 08:45:22

这应该记入https://stackoverflow.com/users/695461/dmoses

实际上,您可以将框架元素的内容窗口对象与消息事件的 event.source 进行比较,如果它们实际上相同,则比较将产生 TRUE。

因此,为了解决我的特定问题,我需要保留我创建的框架元素列表(如果需要,可以在它们上撒上任何附加属性),并且当事件到来时,迭代所有元素,寻找其 contentWindow 属性等于 event.source 属性的一个。

更新

通过遇到一些令人讨厌的错误,我们还发现您应该在从父窗口内创建的 iframe 上放置一个“id”。特别是如果该窗口本身位于 iframe 中。否则,某些(Android 4.x 肯定是已知的)浏览器将产生真实的比较,即使消息是从完全不同的子框架接收的。

This should be credited to https://stackoverflow.com/users/695461/dmoses.

You can actually compare the content window object of the frame element to the event.source of the message event, and the comparison will yield TRUE if they are, in fact, the same.

So, to solve my particular problem, I'll need to keep the list of frame elements that I've created (sprinkling them, if needed, with whatever additional properties), and when the event comes in, iterating through all, looking for one that has its contentWindow property equal to the event.source property.

UPDATE

We did, through encountering some nasty bugs, also found out that you should put an 'id' on the iframe created from within the parent window. Especially if that window is itself in an iframe. Otherwise, certain (Android 4.x being known for sure) browsers will yield true comparison even if the message is being received from a completely different child frame.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文