¿El postMessage de origen cruzado está roto en IE10?

91

Estoy tratando de hacer que un postMessageejemplo trivial funcione ...

  • en IE10
  • entre ventanas / pestañas (frente a iframes)
  • a través de orígenes

Elimine cualquiera de estas condiciones y todo funcionará bien :-)

Pero por lo que puedo decir, entre ventanas postMessagesolo parece funcionar en IE10 cuando ambas ventanas comparten un origen. (Bueno, de hecho, y extrañamente, el comportamiento es un poco más permisivo que eso: dos orígenes diferentes que comparten un host también parecen funcionar).

¿Es este un error documentado? ¿Alguna solución u otro consejo?

(Nota: esta pregunta toca los problemas, pero su respuesta es sobre IE8 e IE9, no sobre 10)


Más detalles + ejemplo ...

demostración de la página del lanzador

<!DOCTYPE html>
<html>
  <script>
    window.addEventListener("message", function(e){
      console.log("Received message: ", e);
    }, false);
  </script>
  <button onclick="window.open('http://jsbin.com/ameguj/1');">
    Open new window
  </button>
</html>

demostración de la página lanzada

<!DOCTYPE html>
<html>
  <script>
    window.opener.postMessage("Ahoy!", "*");
  </script>
</html>

Esto funciona en: http://jsbin.com/ahuzir/1 , porque ambas páginas están alojadas en el mismo origen (jsbin.com). Pero mueva la segunda página a cualquier otro lugar, y fallará en IE10.

Tonterías
fuente
5
Considere cambiar la respuesta aceptada por una que responda a la pregunta en lugar de una que incluya MessageChannel como su mejor opción cuando MessageChannel requiere postMessage para que funcione. Pasé más de una hora jugando con MessageChannel solo para descubrir que la única solución viable es un proxy iframe.
Akrikos
1
Si su window.open es solo un cuadro de diálogo emergente, puede evitarlo por completo y usar un iframe en un modal js. Algo como jQuery Dialog o Bootstrap Modal es cómo lo implementé. Entonces puedes usarlo window.parent.postMessageen IE.
styfle
@Bosh, como mi respuesta parece funcionar en 2018 y no requiere un marco de proxy, ¿le importaría establecer esa como la respuesta aceptada, ya que parece ayudarnos a nosotros, los desafortunados que todavía tenemos que apoyar al viejo ie
Bruno Laurinec

Respuestas:

62

Me equivoqué cuando publiqué originalmente esta respuesta: en realidad no funciona en IE10. Aparentemente, la gente ha encontrado esto útil por otras razones, así que lo dejo para la posteridad. Respuesta original a continuación:


Vale la pena señalar: el enlace en esa respuesta que vinculó a estados que postMessageno es de origen cruzado para ventanas separadas en IE8 e IE9; sin embargo, también se escribió en 2009, antes de que apareciera IE10. Así que no lo tomaría como una indicación de que está arreglado en IE10.

En cuanto a postMessagesí mismo, http://caniuse.com/#feat=x-doc-messaging indica notablemente que todavía está roto en IE10, lo que parece coincidir con su demostración. La página caniuse enlaza con este artículo , que contiene una cita muy relevante:

Internet Explorer 8+ admite parcialmente la mensajería entre documentos: actualmente funciona con iframes, pero no con nuevas ventanas. Internet Explorer 10, sin embargo, admitirá MessageChannel. Actualmente, Firefox admite la mensajería entre documentos, pero no MessageChannel.

Por lo tanto, su mejor MessageChannelopción es probablemente tener una ruta de código basada y recurrir a ella postMessagesi no existe. No obtendrá soporte para IE8 / IE9, pero al menos funcionará con IE10.

Documentos en MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx

ShZ
fuente
8
¿Cómo crearía una MessageChannelruta de código basada en que funcione? Aún necesita funcionar postMessagepara llevar el puerto del canal a la otra ventana.
balpha
1
El uso postMessagecon la nueva MessageChannelAPI funcionará en nuevas ventanas y orígenes. El trabajo es un poco incómodo, supongo, pero básicamente: postMessage('foo', '*')es malo, postMessage('foo', [messageChannel.port2])es bueno.
ShZ
3
No puedo por mi vida hacer que postMessage funcione con una ventana emergente de dominio cruzado usando la última versión de IE (11) y la API de MessageChannel. Y honestamente, no puedo encontrar en ningún otro lugar de InterWebs que no sea esta respuesta que indica que este escenario específico debería funcionar. ¿Alguien puede señalar un ejemplo que demuestre que funciona? Estaría eternamente agradecido.
Todd Menier
4
MessageChannel no debería funcionar por la misma razón que postMessage no lo hará. Microsoft necesita corregir la clasificación de procesos cruzados. blogs.msdn.com/b/ieinternals/archive/2009/09/15/…
EricLaw
9
Esta respuesta es molesta porque nos da falsas esperanzas. La respuesta es: no funcionará sin un proxy porque se requiere postMessage para que MessageChannel funcione (al menos en todas las demostraciones que he visto). A menos que alguien me muestre una demostración de MessageChannel funcionando sin postMessage o postMessage ('name', '<domain>', [messageChannel.port2]) trabajando en varios dominios (no pude hacer que funcione), no lo creeré funciona sin un marco de proxy.
Akrikos
30

Cree una página de proxy en el mismo host que el lanzador. La página proxy tiene una iframefuente con configurada como página remota. PostMessage de origen cruzado ahora funcionará en IE10 así:

  • La página remota se utiliza window.parent.postMessagepara pasar datos a la página proxy. Como utiliza iframes, es compatible con IE10
  • La página de proxy se utiliza window.opener.postMessagepara devolver datos a la página de inicio. Como está en el mismo dominio, no hay problemas de origen cruzado. También puede llamar directamente a métodos globales en la página de inicio si no desea utilizar postMessage, por ejemplo.window.opener.someMethod(data)

Muestra (todas las URL son ficticias)

Página del lanzador en http://example.com/launcher.htm

<!DOCTYPE html>
<html>
    <head>
        <title>Test launcher page</title>
        <link rel="stylesheet" href="/css/style.css" />
    </head>
    <body>

    <script>
        function log(msg) {
            if (!msg) return;

            var logger = document.getElementById('logger');
            logger.value += msg + '\r\n';
        }            

        function toJson(obj) {
            return JSON.stringify(obj, null, 2);
        }

        function openProxy() {
            var url = 'proxy.htm';
            window.open(url, 'wdwProxy', 'location=no');
            log('Open proxy: ' + url);
        }

        window.addEventListener('message', function(e) {
            log('Received message: ' + toJson(e.data));
        }, false);
    </script>
    
    <button onclick="openProxy();">Open remote</button> <br/>
    <textarea cols="150" rows="20" id="logger"></textarea>

    </body>
</html>

Página de proxy en http://example.com/proxy.htm

<!DOCTYPE html>
<html>
    <head>
        <title>Proxy page</title>
        <link rel="stylesheet" href="/css/style.css" />
    </head>
    <body>

    <script>
        function toJson(obj) {
            return JSON.stringify(obj, null, 2);
        }

        window.addEventListener('message', function(e) {
            console.log('Received message: ' + toJson(e.data));

            window.opener.postMessage(e.data, '*');
            window.close(self);
        }, false);
    </script>

    <iframe src="http://example.net/remote.htm" frameborder="0" height="300" width="500" marginheight="0" marginwidth="0" scrolling="auto"></iframe>

    </body>
</html>

Página remota en http://example.net/remote.htm

<!DOCTYPE html>
<html>
    <head>
        <title>Remote page</title>
        <link rel="stylesheet" href="/css/style.css" />
    </head>
    <body>

    <script>
        function remoteSubmit() {
            var data = {
                message: document.getElementById('msg').value
            };

            window.parent.postMessage(data, '*');
        }
    </script>
    
    <h2>Remote page</h2>

    <input type="text" id="msg" placeholder="Type a message" /><button onclick="remoteSubmit();">Close</button>

    </body>
</html>
LyphTEC
fuente
Su respuesta sería mejor si incluyera un enlace a la página de ejemplo de Microsoft y la página de solución alternativa vinculada en otras respuestas. Solución alternativa: blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Ejemplo (de la página de solución alternativa): debugtheweb.com/test/xdm/origin
Akrikos
Además, su página de ejemplo ahora enlaza con una página de GoDaddy que no se encuentra.
Akrikos
8
eh ... todas las URL son EJEMPLOS y no están destinadas a apuntar a páginas existentes ... a partir de la fuente enumerada puede determinar qué se debe hacer para que funcione ..
LyphTEC
Gracias por la aclaración. :-)
Akrikos
29

== SOLUCIÓN DE TRABAJO EN 2020 sin iframe ==

Sobre la base de la respuesta por enredo, tuve éxito en IE11 [y emulé el modo IE10] usando el siguiente fragmento:

var submitWindow = window.open("/", "processingWindow");
submitWindow.location.href = 'about:blank';
submitWindow.location.href = 'remotePage to comunicate with';

Luego pude comunicarme usando la pila típica de postMessage, estoy usando un mensajero estático global en mi escenario (aunque supongo que no tiene ninguna importancia, también estoy adjuntando mi clase de mensajero)

var messagingProvider = {
    _initialized: false,
    _currentHandler: null,

    _init: function () {
        var self = this;
        this._initialized = true;
        var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
        var eventer = window[eventMethod];
        var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

        eventer(messageEvent, function (e) {
            var callback = self._currentHandler;
            if (callback != null) {
                var key = e.message ? "message" : "data";
                var data = e[key];
                callback(data);
            }
        }, false);
    },

    post: function (target, message) {
        target.postMessage(message, '*');
    },

    setListener: function (callback) {
        if (!this._initialized) {
            this._init();
        }

        this._currentHandler = callback;
    }
}

No importa cuánto lo intenté, no pude hacer que las cosas funcionaran en IE9 e IE8

Mi configuración donde está funcionando:
versión de IE: 11.0.10240.16590, versiones de actualización: 11.0.25 (KB3100773)

Bruno Laurinec
fuente
6
Solo tengo que decir, en caso de que alguien más esté mirando esta solución y piense "de ninguna manera, eso no podría solucionarlo", sí, en realidad corrigió la imposibilidad de publicar un mensaje en el window.opener en IE11. Increíble.
dkr88
1
De ninguna manera ... Estuve como 2 días intentándolo y esto "resolvió" el problema
lmiguelmh
funciona como encantos y misterioso !! (IE10.0.9200, win7)
Simon
¿Puede proporcionar un ejemplo completo para esta solución?
msm2020
1
@SidJonnala no realmente, pero lo recomendaría. Si reasigna a la página remota real inmediatamente y su página tarda de 3 a 4 segundos en cargarse [puede suceder de vez en cuando], entonces corre el riesgo de que su página window.open ('/') se cargue y confunda al usuario
Bruno Laurinec
2

Sobre la base de las respuestas de LyphTEC y Akrikos, otra solución es crear una <iframe>ventana emergente en blanco, lo que evita la necesidad de una página de proxy separada, ya que la ventana emergente en blanco tiene el mismo origen que su abridor.

Página del lanzador en http://example.com/launcher.htm

<html>
  <head>
    <title>postMessage launcher</title>
    <script>
      function openWnd() {
        var w = window.open("", "theWnd", "resizeable,status,width=400,height=300"),
            i = w.document.createElement("iframe");

        i.src = "http://example.net/remote.htm";
        w.document.body.appendChild(i);

        w.addEventListener("message", function (e) {
          console.log("message from " + e.origin + ": " + e.data);

          // Send a message back to the source
          e.source.postMessage("reply", e.origin);
        });
      }
    </script>
  </head>
  <body>
    <h2>postMessage launcher</h2>
    <p><a href="javascript:openWnd();">click me</a></p>
  </body>
</html>

Página remota en http://example.net/remote.htm

<html>
  <head>
    <title>postMessage remote</title>
    <script>
      window.addEventListener("message", function (e) {
        alert("message from " + e.origin + ": " + e.data);
      });

      // Send a message to the parent window every 5 seconds
      setInterval(function () {
        window.parent.postMessage("hello", "*");
      }, 5000);
    </script>
  </head>
  <body>
    <h2>postMessage remote</h2>
  </body>
</html>

No estoy seguro de cuán frágil es esto, pero funciona en IE 11 y Firefox 40.0.3.

maraña
fuente
1
... y ahora no funciona (falla silenciosa en la ventana emergente a la <iframe>dirección) en IE 11 ( 11.0.9600.18036, actualizar versiones 11.0.23 (KB3087038)). Posiblemente esté implicada la actualización de seguridad reciente ( KB3087038 ).
enredo
1

En este momento, (2014-09-02), lo mejor que puede hacer es utilizar un marco de proxy como se indica en la publicación del blog msdn que detalla una solución para este problema: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-deployment-issues-in-ie8-and-later /

Aquí está el ejemplo de trabajo: http://www.debugtheweb.com/test/xdm/origin/

Necesita configurar un marco de proxy en su página que tenga el mismo origen que la ventana emergente. Envíe información desde la ventana emergente al marco de proxy utilizando window.opener.frames[0]. Luego use postMessage desde el marco del proxy a la página principal.

Akrikos
fuente
1

Esta solución implica agregar el sitio a los sitios de confianza de Internet Explore y no a los sitios de la intranet local. Probé esta solución en Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 y Windows 7 SP1 / IE 10.0.9200.17148. La página no debe estar incluida en la Zona Intranet .

Así que abra la configuración de Internet Explorer (Herramientas> Opciones de Internet> Seguridad> Sitios de confianza> Sitios) y agregue la página, aquí uso * para hacer coincidir todos los subdominios. Asegúrese de que la página no aparezca en los sitios de la intranet local (Herramientas> Opciones de Internet> Seguridad> Intranet local> Sitios> Avanzado). Reinicie su navegador y vuelva a probar.

Agregar a sitios confiables en Internet Explorer

En Windows 10 / Microsoft Edge , encontrará esta configuración en Panel de control> Opciones de Internet.

ACTUALIZAR

Si esto no funciona, puede intentar restablecer todas sus configuraciones en Herramientas> Opciones de Internet> Configuración avanzada> Restablecer la configuración de Internet Explorer y luego Restablecer: ¡ utilícelo con precaución ! Luego, deberá reiniciar su sistema. Después de eso, agregue los sitios a los sitios de confianza.

Vea en qué zona se encuentra su página en Archivo> Propiedades o haga clic con el botón derecho.

Propiedades de la página en Internet Explorer

ACTUALIZAR

Estoy en una intranet corporativa ya veces funciona y otras no (¿configuración automática? Incluso empecé a culpar al proxy corporativo). Al final usé esta solución https://stackoverflow.com/a/36630058/2692914 .

lmiguelmh
fuente
0

Esta Q es antigua, pero para esto es easyXDM, tal vez compruébelo como una alternativa potencial cuando detecte un navegador que no es compatible con html5 .postMessage:

https://easyxdm.net/

Utiliza el contenedor VBObject y todo tipo de cosas con las que nunca querría tener que lidiar para enviar mensajes de dominio cruzado entre ventanas o marcos donde window.postMessage falla para varias versiones de IE (y tal vez el borde, aún no estoy seguro al 100% del soporte Edge tiene, pero parece que también necesita una solución para .postMessage)

OG Sean
fuente
-3

MessageChannel no funciona para IE 9-11 entre ventanas / pestañas, ya que se basa en postMessage, que todavía está roto en este escenario. La "mejor" solución es llamar a una función a través de window.opener (es decir, window.opener.somefunction ("somedata")).

Solución alternativa con más detalle aquí

usuario1337489
fuente
1
Eso no funciona en configuraciones de origen cruzado, que es uno de los requisitos previos en la pregunta.
PhistucK