Chrome上的window.postMessage问题

use*_*328 12 javascript jquery html5 postmessage cross-domain

我被困在这几个小时.

我在http://example.com上有一个a.html,它在http://subdomain.example.com上包含一个带有src到b.html的iframe .a.html有一些JS代码将postMessage发送到iframe.

postMessage的代码很简单:

iframe_window.postMessage('message', iframe_element.src)
Run Code Online (Sandbox Code Playgroud)

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

Unable to post message to http://subdomain.example.com. Recipient has origin null.
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

iframe_window.postMessage('message', 'http://subdomain.example.com')
Run Code Online (Sandbox Code Playgroud)

但不要运气!

这是它工作的唯一方式:

iframe_window.postMessage('message', '*')
Run Code Online (Sandbox Code Playgroud)

但我听说'*'不好用.

Firefox中没有问题.

Luk*_*ngs 19

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

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

以下是我在没有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)
Run Code Online (Sandbox Code Playgroud)

儿童:

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)
Run Code Online (Sandbox Code Playgroud)

这是一个简单的解决方案,其中,孩子会发信号给任何人,它的加载(使用"*",这是正常的,因为没有任何敏感正在发送.)父监听加载事件,并检查它的,它是有兴趣的孩子在那里发射它.

然后父母向孩子发送消息,孩子准备好接收它.当孩子得到消息时,它将数据放在<h1>中并将其附加到<body>.

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