Parece que esto podría ser un problema con el iframe hijo no cargado en el momento en que se envía la señal, por lo que iframe.src no tiene el valor adecuado.
Hice algunas pruebas y obtuve el mismo error que tú, pero cuando envolví la llamada postMessage en un setTimeout y esperé 100ms, no hubo ningún error, lo que me indica que se trata de una condición de carrera de inicialización.
Así es como he implementado una solución más limpia sin el setTimeout:
Padres:
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)
Niño:
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)
Esta es una solución simple en el que el niño va a señalar a cualquiera que está cargado (usando "*", que está bien, porque no se envía nada sensible). El padre escucha un evento cargado y comprueba que es el hijo que está entre ested en eso lo está emitiendo.
El padre envía un mensaje al niño, que está listo para recibirlo. Cuando el niño recibe el mensaje pone los datos en un <h1> y lo agrega al cuerpo < >.
He probado esto en Chrome con subdominios reales y esta solución funcionó para mí.
Solo para aclarar, en su código actual, ¿está usando un sitio web real? –