O postMessage de origem cruzada está quebrado no IE10?

91

Estou tentando fazer um postMessageexemplo trivial funcionar ...

  • no IE10
  • entre janelas / guias (vs. iframes)
  • através das origens

Remova qualquer uma dessas condições e tudo funcionará bem :-)

Mas, pelo que posso dizer, entre as janelas postMessagesó parece funcionar no IE10 quando ambas as janelas compartilham uma origem. (Bem, na verdade - e estranhamente - o comportamento é um pouco mais permissivo do que isso: duas origens diferentes que compartilham um host parecem funcionar também).

Este é um bug documentado? Alguma solução alternativa ou outro conselho?

(Observação: esta pergunta aborda os problemas, mas sua resposta é sobre o IE8 e o IE9 - não sobre 10)


Mais detalhes + exemplo ...

demonstração da página inicial

<!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>

página de demonstração lançada

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

Funciona em: http://jsbin.com/ahuzir/1 - porque ambas as páginas estão hospedadas na mesma origem (jsbin.com). Mas mova a segunda página para qualquer outro lugar e ela falhará no IE10.

Bosh
fonte
5
Por favor, considere alterar a resposta aceita para uma que responda à pergunta em vez de uma que lista MessageChannel como sua melhor aposta quando MessageChannel requer postMessage para fazê-lo funcionar. Passei mais de uma hora brincando com MessageChannel apenas para descobrir que a única solução viável é um proxy iframe.
Akrikos
1
Se o seu window.open for apenas uma caixa de diálogo pop-up, você pode evitá-la completamente e usar um iframe em um modal js. Algo como o jQuery Dialog ou Bootstrap Modal é como eu o implementei. Então você pode usar window.parent.postMessageno IE.
elegante
@Bosh, como minha resposta parece funcionar em 2018 e não requer moldura de proxy, você se importaria de definir essa uma como a resposta aceita, pois parece nos ajudar, infelizes que ainda têm que apoiar o antigo ie
Bruno Laurinec

Respostas:

62

Eu estava enganado quando postou esta resposta originalmente: na verdade, não funciona no IE10. Aparentemente, as pessoas acharam isso útil por outras razões, então estou deixando para a posteridade. Resposta original abaixo:


Vale a pena observar: o link nessa resposta que você vinculou a afirma que postMessagenão é uma origem cruzada para janelas separadas no IE8 e no IE9 - no entanto, também foi escrito em 2009, antes do IE10 surgir. Então, eu não consideraria isso uma indicação de que foi corrigido no IE10.

Quanto a postMessagesi mesmo, http://caniuse.com/#feat=x-doc-messaging indica que ele ainda não funciona no IE10, o que parece corresponder à sua demonstração. Os links da página caniuse para este artigo , que contém uma citação muito relevante:

O Internet Explorer 8+ oferece suporte parcial para mensagens entre documentos: atualmente funciona com iframes, mas não com novas janelas. O Internet Explorer 10, entretanto, oferece suporte a MessageChannel. O Firefox atualmente oferece suporte a mensagens entre documentos, mas não MessageChannel.

Portanto, sua melhor aposta é provavelmente ter um MessageChannel codepath baseado e voltar para o postMessagecaso não exista. Ele não dará suporte ao IE8 / IE9, mas pelo menos funcionará com o IE10.

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

ShZ
fonte
8
Como você criaria um MessageChannelcodepath baseado em que funcione? Você ainda precisa funcionar postMessagepara levar a porta do canal para a outra janela.
balpha
1
Usar postMessagecom a nova MessageChannelAPI funcionará em novas janelas e origens. O funcionamento é um pouco estranho, eu acho, mas basicamente: postMessage('foo', '*')é ruim, postMessage('foo', [messageChannel.port2])é bom.
ShZ
3
Não consigo fazer postMessage funcionar com uma janela pop-up de domínio cruzado usando a versão mais recente do IE (11) e a API MessageChannel. E, honestamente, não consigo encontrar em nenhum outro lugar na InterWebs que não seja esta resposta indicando que esse cenário específico deve funcionar. Alguém pode apontar um exemplo que prove que funciona? Eu ficaria eternamente grato.
Todd Menier
4
MessageChannel não deve funcionar pelo mesmo motivo que postMessage não funciona. A Microsoft precisa corrigir o empacotamento entre processos. blogs.msdn.com/b/ieinternals/archive/2009/09/15/…
EricLaw
9
Essa resposta é irritante porque nos dá falsas esperanças. A resposta é: ele não funcionará sem um proxy porque postMessage é necessário para fazer o MessageChannel funcionar (pelo menos em todas as demonstrações que vi). A menos que alguém me mostre uma demonstração de MessageChannel funcionando sem postMessage ou postMessage ('name', '<domain>', [messageChannel.port2]) funcionando em vários domínios (não consegui fazer funcionar), não vou acreditar funciona sem um quadro de proxy.
Akrikos
30

Crie uma página proxy no mesmo host que o iniciador. A página proxy tem um iframecom a fonte definida para a página remota. PostMessage de origem cruzada agora funcionará no IE10 assim:

  • Uso de página remota window.parent.postMessage para passar dados para a página proxy. Como usa iframes, é compatível com o IE10
  • A página proxy usa window.opener.postMessagepara passar dados de volta à página inicial. Como se trata do mesmo domínio - não há problemas de origem cruzada. Ele também pode chamar diretamente métodos globais na página inicial se você não quiser usar postMessage - por exemplo.window.opener.someMethod(data)

Amostra (todos os URLs são fictícios)

Página inicial em 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 proxy em 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 em 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
fonte
Sua resposta seria melhor se incluísse um link para a página de exemplo da Microsoft e a página de solução alternativa com link em outras respostas. Solução alternativa: blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Exemplo (da página de solução alternativa): debugtheweb.com/test/xdm/origin
Akrikos
Além disso, sua página de exemplo agora está vinculada a uma página do godaddy não encontrada.
Akrikos
8
Hã? ... todos os URLs são EXEMPLOS e não pretendem realmente apontar para páginas existentes ... a partir da fonte listada, você pode determinar o que precisa ser feito para fazê-lo funcionar ..
LyphTEC
Obrigado pelo esclarecimento. :-)
Akrikos
29

== SOLUÇÃO DE TRABALHO EM 2020 sem iframe ==

Com base no answer by tangle, tive sucesso no IE11 [e emulei o modo IE10] usando o seguinte snippet:

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

Então eu fui capaz de me comunicar usando uma pilha típica de postMessage, estou usando um mensageiro estático global em meu cenário (embora eu não ache que seja significativo, também estou anexando minha classe de mensageiro)

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;
    }
}

Não importa o quanto eu tentei, não consegui fazer as coisas funcionarem no IE9 e IE8

Minha configuração onde está funcionando:
versão do IE: 11.0.10240.16590, versões de atualização: 11.0.25 (KB3100773)

Bruno Laurinec
fonte
6
Eu só tenho que dizer - no caso de alguém estar olhando para esta solução alternativa pensando "de jeito nenhum, isso não poderia consertar" - sim, ele corrigiu a incapacidade de postar a mensagem no window.opener no IE11. Inacreditável.
dkr88 de
1
De jeito nenhum ... Eu estava tipo 2 dias tentando e isso "resolve" o problema
lmiguelmh
funciona como encantos e misteriosos !! (IE10.0.9200, win7)
Simon,
Você pode fornecer um exemplo completo para esta solução alternativa?
msm2020 01 de
1
@SidJonnala não realmente, mas eu recomendaria isso. Se você reatribuir à página remota real imediatamente e sua página demorar 3-4s para carregar [pode acontecer de vez em quando], você corre o risco de que sua página window.open ('/') carregue e confunda o usuário
Bruno Laurinec
2

Com base nas respostas de LyphTEC e Akrikos, outra solução alternativa é criar um <iframe>dentro de uma janela pop-up em branco, o que evita a necessidade de uma página proxy separada, já que o pop-up em branco tem a mesma origem de seu abridor.

Página inicial em 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 em 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>

Não tenho certeza de como isso é frágil, mas está funcionando no IE 11 e Firefox 40.0.3.

emaranhado
fonte
1
... e agora não funciona (falha silenciosa na janela pop-up para <iframe>direcionar) no IE 11 ( 11.0.9600.18036versões de atualização 11.0.23 (KB3087038)). Possivelmente, a atualização de segurança recente ( KB3087038 ) está implicada.
emaranhado de
1

No momento, (02-09-2014), sua melhor aposta é usar um quadro de proxy, conforme observado na postagem do blog do msdn que detalha uma solução alternativa para esse problema: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-deployment-issues-in-ie8-and-later /

Aqui está o exemplo de trabalho: http://www.debugtheweb.com/test/xdm/origin/

Você precisa configurar um quadro de proxy em sua página que tenha a mesma origem do pop-up. Envie informações do pop-up para o quadro de proxy usando window.opener.frames[0]. Em seguida, use postMessage do quadro de proxy para a página principal.

Akrikos
fonte
1

Esta solução envolve adicionar o site aos sites confiáveis ​​do Internet Explorer e não aos sites da intranet local. Testei essa solução no Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 e Windows 7 SP1 / IE 10.0.9200.17148. A página não deve ser incluída na Zona da Intranet .

Portanto, abra a configuração do Internet Explorer (Ferramentas> Opções da Internet> Segurança> Sites confiáveis> Sites) e adicione a página, aqui eu uso * para corresponder a todos os subdomínios. Certifique-se de que a página não esteja listada nos sites da intranet local (Ferramentas> Opções da Internet> Segurança> Intranet local> Sites> Avançado). Reinicie seu navegador e teste novamente.

Adicionar sites confiáveis ​​no Internet Explorer

No Windows 10 / Microsoft Edge você encontrará essa configuração em Painel de Controle> Opções da Internet.

ATUALIZAR

Se isso não funcionar, você pode tentar redefinir todas as suas configurações em Ferramentas> Opções da Internet> Configurações avançadas> Redefinir as configurações do Internet Explorer e depois Redefinir: use com cuidado ! Em seguida, você precisará reinicializar o sistema. Depois disso, adicione os sites aos sites confiáveis.

Veja em qual zona sua página está em Arquivo> Propriedades ou clicando com o botão direito.

Propriedades da página no Internet Explorer

ATUALIZAR

Estou em uma intranet corporativa e às vezes funciona e às vezes não (configuração automática? Comecei até a culpar o proxy corporativo). No final, usei essa solução https://stackoverflow.com/a/36630058/2692914 .

lmiguelmh
fonte
0

Este Q é antigo, mas é para isso que serve o easyXDM, talvez verifique-o como uma alternativa potencial ao detectar um navegador que não oferece suporte a html5 .postMessage:

https://easyxdm.net/

Ele usa VBObject wrapper e todos os tipos de coisas que você nunca gostaria de ter que lidar para enviar mensagens de domínio cruzado entre janelas ou frames onde window.postMessage falha para várias versões do IE (e talvez edge, ainda não tenho 100% de certeza sobre o suporte O Edge, mas parece que também precisa de uma solução alternativa para .postMessage)

OG Sean
fonte
-3

MessageChannel não funciona para o IE 9-11 entre janelas / guias, pois depende de postMessage, que ainda não funciona neste cenário. A "melhor" solução alternativa é chamar uma função por meio de window.opener (ou seja, window.opener.somefunction ("somedata")).

Solução alternativa em mais detalhes aqui

user1337489
fonte
1
Isso não funciona em configurações de origem cruzada, que é um dos pré-requisitos da questão.
PhistucK de