Como você usa window.postMessage entre domínios?

89

Parece que o objetivo de window.postMessage é permitir a comunicação segura entre janelas / frames hospedados em domínios diferentes, mas na verdade não parece permitir isso no Chrome.

Este é o cenário:

  1. Incorpore um <iframe> (com um srcno domínio B * ) em uma página no domínio A
  2. O <iframe> acaba sendo principalmente uma tag <script>, no final da execução ...
  3. Eu chamo window.postMessage ( some_data , page_on_A )

O <iframe> está definitivamente no contexto do domínio B, e eu confirmei que o javascript embutido naquele <iframe> é executado corretamente e chama postMessagecom os valores corretos.

Recebo esta mensagem de erro no Chrome:

Não é possível para postar mensagem para A . Destinatário tem origem B .

Este é o código que registra um listener de evento de mensagem na página A:

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

Também tentei ligar window.postMessage(some_data, '*'), mas tudo o que faço é suprimir o erro.

Estou apenas perdendo o ponto aqui, window.postMessage (...) não foi feito para isso? Ou estou apenas fazendo terrivelmente errado?

* Mime-type text / html, que deve permanecer.

Kevin Montrose
fonte
1
Você provavelmente já sabe disso, mas o MDC tem um excelente resumo sobre postMessage: developer.mozilla.org/en/DOM/window.postMessage Para a implementação do FF obviamente, mas talvez haja algo lá que explique por que não funciona.
Pekka

Respostas:

79

Aqui está um exemplo que funciona no Chrome 5.0.375.125.

A página B (conteúdo do iframe):

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

Observe o uso de top.postMessageou parent.postMessagenão window.postMessageaqui

A 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 e B devem ser algo como http://domain.com

EDITAR:

De outra pergunta , parece que os domínios (A e B aqui) devem ter um /para postMessageque funcione corretamente.

Microfone
fonte
3
Quando a página A verifica a origem da mensagem, a origem NÃO conterá um '/' final. Não parece importar se a página B especifica um '/' final ou não. A outra coisa a observar é que os URLs devem ser URLs absolutos.
Catch22 de
1
Essa resposta me deixou um pouco confuso e ainda procurando uma resposta. blog.teamtreehouse.com/cross-domain-messaging-with-postmessage contém uma explicação muito boa sobre o postMessage. O importante é que o emissor da mensagem conheça o domínio do receptor. No exemplo acima, A e B não precisam ser os mesmos domínios, mas B deve saber exatamente qual domínio é usado por A.
Greg Bogumil
7
A questão é sobre vários domínios. A resposta aceita é sobre o mesmo domínio.
empilhamento de
@stackular, não exatamente. A e B podem ser qualquer domínio. Essa é a principal razão de terpostMessage
Mic
1
+1. Queremos confirmar se essa solução funcionou em nosso caso. Temos uma página que contém um iframe de domínio diferente . Observe que isso só funciona no navegador Chrome, pois no firefox precisamos usar window.parent.postMessage em vez de top . Embora não saibamos se isso pode ser aplicado a qualquer outro navegador.
rahmatns
24

Você deve postar uma mensagem do quadro ao pai, depois de carregada.

script de quadro:

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

E ouça no pai:

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

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

Use este link para obter mais informações: http://en.wikipedia.org/wiki/Web_Messaging

Golyo
fonte
2

Provavelmente você está tentando enviar seus dados de mydomain.com para www.mydomain.com ou vice-versa, NOTE que você perdeu "www". http://mydomain.com e http://www.mydomain.com são domínios diferentes para javascript.

Getoriks
fonte
2
Em um projeto que estou fazendo, estou usando file:/// É possível obter erros de domínio ao extrair conteúdo apenas do sistema de arquivos local?
Jacksonkr