Javascript Chrome 上 window.postMessage 的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12641146/
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-08-23 10:55:40  来源:igfitidea点击:

Problems with window.postMessage on Chrome

javascriptjqueryhtmlcross-domainpostmessage

提问by user1437328

I have been stuck on this for hours.

我已经坚持了几个小时。

I have a.html on http://example.comthat contains an iframe with src to b.html on http://subdomain.example.com. a.html has some JS code to postMessage to the iframe.

我在http://example.com上有一个a.html,其中包含一个 iframe,其中 src 到http://subdomain.example.com上的 b.html 。a.html 有一些 JS 代码来 postMessage 到 iframe。

The code to postMessage is simple:

postMessage 的代码很简单:

iframe_window.postMessage('message', iframe_element.src)

But this way, Chrome throws an error:

但是这样一来,Chrome 就抛出了一个错误:

Unable to post message to http://subdomain.example.com. Recipient has origin null.

I have also tried:

我也试过:

iframe_window.postMessage('message', 'http://subdomain.example.com')

But NO LUCK!

但没有运气!

This is the ONLY WAY it works:

这是它工作的唯一方式:

iframe_window.postMessage('message', '*')

But I have heard '*' is not good to use.

但是我听说'*'不好用。

No problems in Firefox.

在 Firefox 中没有问题。

回答by Luke Channings

It looks like this might be an issue with the child iframe not being loaded at the time the signal is sent, thus iframe.src doesn't have the proper value.

看起来这可能是发送信号时未加载子 iframe 的问题,因此 iframe.src 没有正确的值。

I did some testing and got the same error as you, but when I wrapped the postMessage call in a setTimeout and waited 100ms then there was no error, which tells me that this is an initialisation race condition.

我做了一些测试并得到了与您相同的错误,但是当我将 postMessage 调用包装在 setTimeout 中并等待 100 毫秒时,没有错误,这告诉我这是一个初始化竞争条件。

Here's how I implemented a cleaner solution without the setTimeout:

以下是我如何在没有 setTimeout 的情况下实现更清洁的解决方案:

Parent:

家长:

window.addEventListener("DOMContentLoaded", function() {

    var iframe = document.querySelector("iframe")
      , _window = iframe.contentWindow

    window.addEventListener("message", function(e) {

        // wait for child to signal that it's loaded.
        if ( e.data === "loaded" && e.origin === iframe.src.split("/").splice(0, 3).join("/")) {

            // send the child a message.
            _window.postMessage("Test", iframe.src)
        }
    })

}, false)

Child:

孩子:

window.addEventListener("DOMContentLoaded", function() {

    // signal the parent that we're loaded.
    window.parent.postMessage("loaded", "*")

    // listen for messages from the parent.
    window.addEventListener("message", function(e) {

        var message = document.createElement("h1")

        message.innerHTML = e.data

        document.body.appendChild(message)

    }, false)

}, false)

This is a simple solution in which the child will signal to anyone that it's loaded (using "*", which is okay, because nothing sensitive is being sent.) The parent listens for a loaded event and checks that it's the child that it's interested in that's emitting it.

这是一个简单的解决方案,其中子级将向任何人发出它已加载的信号(使用“*”,这是可以的,因为没有发送任何敏感内容。)父级侦听加载的事件并检查它是否是它感兴趣的子级在那发射它。

The parent then sends a message to the child, which is ready to receive it. When the child gets the message it puts the data in an <h1> and appends that to the <body>.

然后,父节点向准备接收消息的子节点发送消息。当孩子收到消息时,它会将数据放入 <h1> 并将其附加到 <body>。

I tested this in Chrome with actual subdomains and this solution worked for me.

我在 Chrome 中使用实际的子域对此进行了测试,此解决方案对我有用。