PostMessage cross-origin è danneggiato in IE10?


91

Sto cercando di far funzionare un postMessageesempio banale ...

  • in IE10
  • tra finestre / schede (rispetto a iframe)
  • attraverso le origini

Rimuovi una qualsiasi di queste condizioni e le cose funzionano bene :-)

Ma per quanto ne so, tra le finestre postMessagesembra funzionare solo in IE10 quando entrambe le finestre condividono un'origine. (Beh, in effetti - e stranamente - il comportamento è leggermente più permissivo di così: anche due origini diverse che condividono un host sembrano funzionare).

È un bug documentato? Eventuali soluzioni alternative o altri consigli?

(Nota: questa domanda tocca i problemi, ma la sua risposta riguarda IE8 e IE9, non 10)


Maggiori dettagli + esempio ...

demo della pagina di avvio

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

ha lanciato la demo della pagina

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

Funziona su: http://jsbin.com/ahuzir/1 - perché entrambe le pagine sono ospitate nella stessa origine (jsbin.com). Ma sposta la seconda pagina da qualche altra parte e non funziona in IE10.



5
Si prega di considerare di cambiare la risposta accettata con una che risponda alla domanda piuttosto che una che elenca MessageChannel come la soluzione migliore quando MessageChannel richiede postMessage per farlo funzionare. Ho passato più di un'ora a giocare con MessageChannel solo per scoprire che l'unica soluzione praticabile è un proxy iframe.
Akrikos

1
Se il tuo window.open è solo una finestra di dialogo popup, potresti evitarlo del tutto e utilizzare un iframe in un js modal. Qualcosa come jQuery Dialog o Bootstrap Modal è come l'ho implementato. Quindi puoi usare window.parent.postMessagein IE.
stile

@Bosh poiché la mia risposta sembra funzionare nel 2018 e non richiede frame proxy, ti dispiacerebbe impostarla come risposta accettata in quanto sembra aiutare noi, sfortunati che devono ancora supportare il vecchio ie
Bruno Laurinec

Risposte:


62

Mi sono sbagliato quando ho originariamente pubblicato questa risposta: in realtà non funziona in IE10. Apparentemente le persone lo hanno trovato utile per altri motivi, quindi lo lascio ai posteri. Risposta originale di seguito:


Vale la pena notare: il collegamento in quella risposta è collegato a stati che postMessagenon sono cross origin per finestre separate in IE8 e IE9 - tuttavia, è stato scritto anche nel 2009, prima che IE10 fosse disponibile. Quindi non lo prenderei come un'indicazione che è stato risolto in IE10.

Quanto a postMessagese stesso, http://caniuse.com/#feat=x-doc-messaging indica in particolare che è ancora rotto in IE10, il che sembra corrispondere alla tua demo. La pagina caniuse si collega a questo articolo , che contiene una citazione molto pertinente:

Internet Explorer 8+ supporta parzialmente la messaggistica tra documenti: attualmente funziona con iframe, ma non con nuove finestre. Internet Explorer 10, tuttavia, supporterà MessageChannel. Firefox attualmente supporta la messaggistica tra documenti, ma non MessageChannel.

Quindi la soluzione migliore è probabilmente quella di avere un MessageChannelcodepath basato e ripiegare su postMessagese non esiste. Non ti darà il supporto per IE8 / IE9, ma almeno funzionerà con IE10.

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


8
Come MessageChannelcreeresti un codepath basato su che funzioni? Hai ancora bisogno di funzionare postMessageper portare la porta del canale all'altra finestra.
balpha

1
L'utilizzo postMessagecon la nuova MessageChannelAPI funzionerà su nuove finestre e origini. Il funzionamento è un po 'imbarazzante immagino, ma in fondo: postMessage('foo', '*')va male, postMessage('foo', [messageChannel.port2])va bene.
ShZ

3
Per tutta la vita non posso far funzionare postMessage con una finestra popup interdominio utilizzando l'ultima versione di IE (11) e l'API MessageChannel. E onestamente non riesco a trovare altrove su InterWeb oltre a questa risposta che indica che questo scenario specifico dovrebbe funzionare. Qualcuno può indicare un esempio che dimostri che funziona? Sarei grato per sempre.
Todd Menier

4
MessageChannel non dovrebbe funzionare per lo stesso motivo per cui postMessage non funziona. Microsoft deve correggere il marshalling tra processi. blogs.msdn.com/b/ieinternals/archive/2009/09/15/…
EricLaw

9
Questa risposta è fastidiosa perché ci dà false speranze. La risposta è: non funzionerà senza un proxy perché postMessage è necessario per far funzionare MessageChannel (almeno in ogni demo che ho visto). A meno che qualcuno non mi mostri una demo di MessageChannel che funziona senza postMessage o postMessage ('name', '<domain>', [messageChannel.port2]) che funziona su più domini (non sono riuscito a farlo funzionare), non ci credo funziona senza un frame proxy.
Akrikos

30

Crea una pagina proxy sullo stesso host del programma di avvio. La pagina proxy ha un'origine iframeimpostata su pagina remota. PostMessage cross-origin ora funzionerà in IE10 in questo modo:

  • La pagina remota utilizza window.parent.postMessageper passare i dati alla pagina proxy. Poiché utilizza iframe, è supportato da IE10
  • La pagina proxy viene utilizzata window.opener.postMessageper ritrasmettere i dati alla pagina di avvio. Poiché si trova sullo stesso dominio, non ci sono problemi tra le origini. Può anche chiamare direttamente metodi globali sulla pagina del launcher se non vuoi usare postMessage - es.window.opener.someMethod(data)

Esempio (tutti gli URL sono fittizi)

Pagina di avvio su 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>

Pagina del proxy all'indirizzo 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>

Pagina remota su 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>

La tua risposta sarebbe migliore se includesse un collegamento alla pagina di esempio di Microsoft e alla pagina della soluzione alternativa collegata ad altre risposte. Soluzione: blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Esempio (dalla pagina della soluzione alternativa): debugtheweb.com/test/xdm/origin
Akrikos

Inoltre, la tua pagina di esempio ora si collega a una pagina di Godaddy non trovata.
Akrikos

8
eh? ... tutti gli URL sono ESEMPI e non intendono puntare effettivamente a pagine esistenti ... dalla fonte elencata puoi determinare cosa è necessario fare per farlo funzionare ..
LyphTEC

Grazie per il chiarimento. :-)
Akrikos

29

== SOLUZIONE FUNZIONANTE NEL 2020 senza iframe ==

Basandomi sulla risposta di tangle, ho avuto successo in IE11 [e la modalità IE10 emulata] utilizzando il seguente frammento:

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

Quindi sono stato in grado di comunicare usando il tipico stack postMessage, sto usando un messenger statico globale nel mio scenario (anche se non suppongo che abbia alcun significato, sto anche allegando la mia classe di messenger)

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

Non importa quanto ci ho provato, non sono riuscito a far funzionare le cose su IE9 e IE8

La mia configurazione in cui funziona:
versione IE: 11.0.10240.16590, versioni di aggiornamento: 11.0.25 (KB3100773)


6
Devo solo dire - nel caso in cui qualcun altro stia guardando questa soluzione alternativa pensando "no, non è possibile risolverla" - sì, in realtà ha risolto l'impossibilità di postMessage al window.opener in IE11. Incredibile.
dkr88


funziona come un fascino e misterioso !! (IE10.0.9200, win7)
Simon

Potete fornire un esempio completo per questa soluzione alternativa?
msm2020

1
@SidJonnala non proprio, ma lo consiglierei. Se riassegni immediatamente alla pagina remota effettiva e la tua pagina impiega 3-4 secondi per caricarsi [potrebbe accadere di tanto in tanto], rischi che la tua pagina window.open ('/') carichi e confonda l'utente
Bruno Laurinec

2

Basandosi sulle risposte di LyphTEC e Akrikos, un'altra soluzione è creare una <iframe>finestra popup all'interno di una finestra popup vuota, che evita la necessità di una pagina proxy separata, poiché il popup vuoto ha la stessa origine del suo apri.

Pagina di avvio su 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>

Pagina remota su 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>

Non sono sicuro di quanto sia fragile, ma funziona in IE 11 e Firefox 40.0.3.


1
... e ora non funziona (errore silenzioso nella finestra popup in <iframe>direzione) in IE 11 ( 11.0.9600.18036, versioni di aggiornamento 11.0.23 (KB3087038)). Probabilmente è implicato il recente aggiornamento della protezione ( KB3087038 ).
Tangle

1

In questo momento, (2014-09-02), la soluzione migliore è utilizzare un frame proxy come indicato nel post del blog msdn che descrive in dettaglio una soluzione alternativa per questo problema: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / problemi-di-implementazione-html5-in-ie8-e-successivi /

Ecco l'esempio funzionante: http://www.debugtheweb.com/test/xdm/origin/

È necessario impostare un frame proxy sulla pagina che abbia la stessa origine del popup. Invia informazioni dal popup al frame proxy utilizzando window.opener.frames[0]. Quindi usa postMessage dal frame proxy alla pagina principale.


1

Questa soluzione prevede l'aggiunta del sito ai siti attendibili di Internet Explorer e non ai siti Intranet locali. Ho testato questa soluzione in Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 e Windows 7 SP1 / IE 10.0.9200.17148. La pagina non deve essere inclusa nella zona Intranet .

Quindi apri la configurazione di Internet Explorer (Strumenti> Opzioni Internet> Sicurezza> Siti attendibili> Siti) e aggiungi la pagina, qui uso * per abbinare tutti i sottodomini. Assicurati che la pagina non sia elencata nei siti Intranet locale (Strumenti> Opzioni Internet> Protezione> Intranet locale> Siti> Avanzate). Riavvia il browser e prova di nuovo.

Aggiungi a siti attendibili in Internet Explorer

In Windows 10 / Microsoft Edge troverai questa configurazione in Pannello di controllo> Opzioni Internet.

AGGIORNARE

Se non funziona puoi provare a ripristinare tutte le tue impostazioni in Strumenti> Opzioni Internet> Impostazioni avanzate> Ripristina impostazioni di Internet Explorer e poi Ripristina: usalo con cautela ! Quindi dovrai riavviare il sistema. Successivamente, aggiungi i siti ai siti attendibili.

Guarda in quale zona si trova la tua pagina in File> Proprietà o usando il tasto destro.

Proprietà della pagina in Internet Explorer

AGGIORNARE

Sono in una intranet aziendale ea volte funziona ea volte no (configurazione automatica? Ho persino iniziato a dare la colpa al proxy aziendale). Alla fine ho usato questa soluzione https://stackoverflow.com/a/36630058/2692914 .


0

Questa Q è vecchia ma questo è lo scopo di easyXDM, forse controllalo come potenziale fallback quando rilevi un browser che non supporta html5 .postMessage:

https://easyxdm.net/

Utilizza il wrapper VBObject e tutti i tipi di cose che non vorresti mai avere a che fare per inviare messaggi interdominio tra finestre o frame in cui window.postMessage fallisce per varie versioni di IE (e forse edge, ancora non sono sicuro al 100% sul supporto Edge ha ma sembra che abbia anche bisogno di una soluzione alternativa per .postMessage)


-3

MessageChannel non funziona per IE 9-11 tra finestre / schede poiché si basa su postMessage, che è ancora rotto in questo scenario. La soluzione "migliore" è chiamare una funzione tramite window.opener (ad esempio window.opener.somefunction ("somedata")).

Soluzione più dettagliata qui


1
Ciò non funziona nelle impostazioni di origine incrociata, che è uno dei prerequisiti della domanda.
PhistucK
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.