17

我已经坚持了几个小时。

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

postMessage 的代码很简单:

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

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

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

我也试过:

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

但没有运气!

这是它工作的唯一方式:

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

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

火狐没有问题。

4

2 回答 2

27

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

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

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

家长:

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)

孩子:

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)

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

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

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

于 2012-12-15T02:23:58.073 回答
0

A shorter solution is to wrap the postMessage inside iframe_element.onload function.

于 2021-07-29T14:48:52.617 回答