2012-09-28 9 views
9

Ich bin seit Stunden darauf festgefahren.Probleme mit window.postMessage auf Chrome

Ich habe a.html auf http://example.com, die einen iframe mit src zu b.html auf http://subdomain.example.com enthält. a.html hat einen JS-Code , um postMessage an den iframe zu senden.

Der Code zum postmessage ist einfach:

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

Aber auf diese Weise, wirft Chrome einen Fehler:

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

ich auch versucht:

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

aber kein Glück!

Dies ist der einzige Weg, es funktioniert:

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

Aber ich gehört habe ‚*‘ ist nicht gut zu verwenden.

Keine Probleme in Firefox.

+0

Nur um zu verdeutlichen, verwenden Sie in Ihrem tatsächlichen Code eine echte Website? –

Antwort

15

Es sieht so aus, als könnte dies ein Problem sein, wenn der untergeordnete Iframe zum Zeitpunkt des Sendens des Signals nicht geladen wird, daher hat iframe.src nicht den richtigen Wert.

Ich habe ein paar Tests und habe den gleichen Fehler wie du, aber wenn ich den PostMessage-Aufruf in einem setTimeout umhüllte und 100ms wartete, dann gab es keinen Fehler, der mir sagt, dass dies eine Initialisierung Race-Bedingung ist.

Hier ist, wie ich eine sauberere Lösung ohne die setTimeout implementiert:

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) 

Kind:

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) 

Dies ist eine einfache Lösung, in der das Kind jedes Signal wird dass es geladen ist (mit "*", was in Ordnung ist, weil nichts Sensitives gesendet wird). Das Elternteil hört auf ein geladenes Ereignis und prüft, ob es das Kind ist, das es inter ist in dem es emittiert.

Der Eltern sendet dann eine Nachricht an das Kind, das bereit ist, es zu empfangen. Wenn das Kind die Nachricht erhält, legt es die Daten in eine <h1> und hängt diese an die < Körper >.

Ich habe dies in Chrome mit tatsächlichen Subdomains getestet und diese Lösung hat für mich funktioniert.

+0

Der allererste Satz 'Es sieht so aus, als wäre dies ein Problem, wenn der Kind-Iframe zum Zeitpunkt des Sendens des Signals nicht geladen wurde', war der Schlüssel, den ich brauchte, um die Iframe-Kommunikation funktionieren zu lassen ... Danke! – RamRaider