¿Cómo se usa window.postMessage en todos los dominios?

89

Parece que el objetivo de window.postMessage es permitir la comunicación segura entre ventanas / marcos alojados en diferentes dominios, pero en realidad no parece permitir eso en Chrome.

Este es el escenario:

  1. Incrustar un <iframe> (con a srcen el dominio B * ) en una página en el dominio A
  2. El <iframe> termina siendo principalmente una etiqueta <script>, al final de la cual se ejecuta ...
  3. Llamo window.postMessage ( some_data , page_on_A )

El <iframe> está definitivamente en el contexto del dominio B, y he confirmado que el javascript incrustado en ese <iframe> se ejecuta correctamente y llama postMessagecon los valores correctos.

Recibo este mensaje de error en Chrome:

No se puede enviar mensaje a una . Destinatario tiene origen B .

Aquí está el código que registra un detector de eventos de mensajes en la página de A:

window.addEventListener(
  "message",
  function (event) {
    // Do something
  },
  false);

También intenté llamar window.postMessage(some_data, '*'), pero todo lo que hace es suprimir el error.

¿Me estoy perdiendo el punto aquí, window.postMessage (...) no está destinado a esto? ¿O simplemente lo estoy haciendo horriblemente mal?

* Texto / html tipo mimo, que debe permanecer.

Kevin Montrose
fuente
1
Probablemente ya sepa esto, pero MDC tiene un resumen excelente en postMessage: developer.mozilla.org/en/DOM/window.postMessage Para la implementación de FF obviamente, pero tal vez haya algo allí que explique por qué no funciona.
Pekka

Respuestas:

79

Aquí hay un ejemplo que funciona en Chrome 5.0.375.125.

La página B (contenido de iframe):

<html>
    <head></head>
    <body>
        <script>
            top.postMessage('hello', 'A');
        </script>
    </body>
</html>

Tenga en cuenta el uso de top.postMessageo parent.postMessageno window.postMessageaquí

La página A:

<html>
<head></head>
<body>
    <iframe src="B"></iframe>
    <script>
        window.addEventListener( "message",
          function (e) {
                if(e.origin !== 'B'){ return; } 
                alert(e.data);
          },
          false);
    </script>
</body>
</html>

A y B deben ser algo así como http://domain.com

EDITAR:

Desde otra pregunta , parece que los dominios (A y B aquí) deben tener un /para postMessageque funcione correctamente.

Micrófono
fuente
3
Cuando la página A verifica el origen del mensaje, el origen NO contendrá un '/' al final. No parece importar si la página B especifica un '/' final o no. La otra cosa a tener en cuenta es que las URL deben ser URL absolutas.
Captura
1
Esta respuesta me dejó un poco confundido y aún buscando una respuesta. blog.teamtreehouse.com/cross-domain-messaging-with-postmessage contiene una muy buena explicación del postMessage. Lo importante es que el remitente del mensaje conozca el dominio del receptor. En el ejemplo anterior, A y B no tienen que ser los mismos dominios, pero B debe saber exactamente qué dominio usa A.
Greg Bogumil
7
La pregunta es sobre dominios cruzados. La respuesta aceptada es sobre el mismo dominio.
stackular
@stackular, no exactamente. A y B pueden ser cualquier dominio. Esa es la razón principal de tenerpostMessage
Mic
1
+1. Queremos confirmar que esta solución funcionó en nuestro caso. Tenemos una página que contiene un iframe de un dominio diferente . Tenga en cuenta que esto solo funciona en el navegador Chrome, ya que en Firefox necesitamos usar window.parent.postMessage en lugar de top . Aunque no sabemos si esto se puede aplicar a cualquier otro navegador.
rahmatns
24

Debe publicar un mensaje desde el marco al padre, después de cargarlo.

script de marco:

$(document).ready(function() {
    window.parent.postMessage("I'm loaded", "*");
});

Y escúchalo en padre:

function listenMessage(msg) {
    alert(msg);
}

if (window.addEventListener) {
    window.addEventListener("message", listenMessage, false);
} else {
    window.attachEvent("onmessage", listenMessage);
}

Utilice este enlace para obtener más información: http://en.wikipedia.org/wiki/Web_Messaging

Golyo
fuente
2

Probablemente intente enviar sus datos de midominio.com a www.mydomain.com o al revés, NOTA que se perdió "www". http://mydomain.com y http://www.mydomain.com son dominios diferentes a javascript.

Getoriks
fuente
2
En un proyecto que estoy haciendo, estoy usando file:/// ¿Es posible obtener errores de dominio al extraer contenido únicamente del sistema de archivos local?
Jacksonkr