Ist die originenspezifische postMessage in IE10 fehlerhaft?

91

Ich versuche, ein triviales postMessageBeispiel zum Laufen zu bringen ...

  • in IE10
  • zwischen Windows / Tabs (vs. Iframes)
  • über Ursprünge hinweg

Entfernen Sie eine dieser Bedingungen, und alles funktioniert einwandfrei :-)

Soweit ich das postMessagebeurteilen kann, scheint das Zwischenfenster in IE10 nur zu funktionieren, wenn beide Fenster einen gemeinsamen Ursprung haben. (Tatsächlich - und seltsamerweise - ist das Verhalten etwas freizügiger: Zwei verschiedene Ursprünge, die sich einen Host teilen, scheinen ebenfalls zu funktionieren.)

Ist das ein dokumentierter Fehler? Irgendwelche Problemumgehungen oder andere Ratschläge?

(Hinweis: Diese Frage berührt die Probleme, aber ihre Antwort bezieht sich auf IE8 und IE9 - nicht auf 10)


Weitere Details + Beispiel ...

Demo der Startseite

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

ins Leben gerufen Seite Demo

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

Dies funktioniert unter: http://jsbin.com/ahuzir/1 - da beide Seiten am selben Ursprung gehostet werden (jsbin.com). Verschieben Sie die zweite Seite jedoch an eine andere Stelle, und dies schlägt in IE10 fehl.

Bosh
quelle
5
Bitte ändern Sie die akzeptierte Antwort in eine, die die Frage beantwortet, anstatt eine, in der MessageChannel als Ihre beste Wahl aufgeführt ist, wenn MessageChannel postMessage benötigt, damit es funktioniert. Ich habe über eine Stunde mit MessageChannel gespielt und festgestellt, dass die einzig praktikable Lösung ein Iframe-Proxy ist.
Akrikos
1
Wenn Ihr window.open nur ein Popup-Dialogfeld ist, können Sie es ganz vermeiden und einen Iframe in einem js-Modal verwenden. So etwas wie jQuery Dialog oder Bootstrap Modal habe ich implementiert. Dann können Sie window.parent.postMessageim IE verwenden.
Styfle
@Bosh, da meine Antwort im Jahr 2018 zu funktionieren scheint und keinen Proxy-Frame erfordert, würde es Ihnen etwas ausmachen, diese als akzeptierte Antwort festzulegen, da sie uns zu helfen scheint, unglückliche, die noch alte unterstützen müssen, dh
Bruno Laurinec

Antworten:

62

Ich habe mich geirrt, als ich diese Antwort ursprünglich gepostet habe: Sie funktioniert in IE10 nicht wirklich. Anscheinend haben die Leute dies aus anderen Gründen nützlich gefunden, also überlasse ich es der Nachwelt. Ursprüngliche Antwort unten:


Bemerkenswert: Der Link in dieser Antwort, den Sie mit Staaten verknüpft haben, die postMessagefür separate Fenster in IE8 und IE9 nicht kreuzübergreifend sind, wurde jedoch auch 2009 geschrieben, bevor IE10 auf den Markt kam. Ich würde das also nicht als Hinweis darauf nehmen, dass es in IE10 behoben ist.

Was postMessagesich http://caniuse.com/#feat=x-doc-messaging zeigt vor allem , dass es noch in IE10 gebrochen hat, die mit Ihrem Demo übereinstimmen scheint. Die caniuse Seite verweist auf diesen Artikel , der ein sehr relevantes Zitat enthält:

Internet Explorer 8+ unterstützt teilweise dokumentübergreifendes Messaging: Es funktioniert derzeit mit Iframes, jedoch nicht mit neuen Fenstern. Internet Explorer 10 unterstützt jedoch MessageChannel. Firefox unterstützt derzeit dokumentübergreifendes Messaging, nicht jedoch MessageChannel.

Ihre beste MessageChannelWahl ist also wahrscheinlich, einen basierten Codepfad zu haben und auf diesen zurückzugreifen, postMessagewenn dieser nicht existiert. Sie erhalten keine IE8 / IE9-Unterstützung, aber zumindest funktioniert es mit IE10.

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

ShZ
quelle
8
Wie würden Sie einen MessageChannelfunktionierenden Codepfad erstellen , der funktioniert? Sie müssen noch funktionieren postMessage, um den Port des Kanals zum anderen Fenster zu bringen.
Balpha
1
Die Verwendung postMessagemit der neuen MessageChannelAPI funktioniert in neuen Fenstern und Ursprüngen. Die Arbeit ist etwas umständlich, denke ich, aber im Grunde: postMessage('foo', '*')ist schlecht, postMessage('foo', [messageChannel.port2])ist gut.
ShZ
3
Ich kann postMessage für mein ganzes Leben nicht mit einem domänenübergreifenden Popup-Fenster arbeiten lassen, das die neueste Version von IE (11) und die MessageChannel-API verwendet. Und ehrlich gesagt kann ich auf den InterWebs nichts anderes finden als diese Antwort, die darauf hinweist, dass dieses spezielle Szenario funktionieren sollte. Kann jemand auf ein Beispiel verweisen, das beweist, dass es funktioniert? Ich wäre für immer dankbar.
Todd Menier
4
MessageChannel sollte aus demselben Grund nicht funktionieren, aus dem postMessage dies nicht tut. Microsoft muss das prozessübergreifende Marshalling beheben. blogs.msdn.com/b/ieinternals/archive/2009/09/15/…
EricLaw
9
Diese Antwort ist ärgerlich, weil sie uns falsche Hoffnung gibt. Die Antwort lautet: Ohne Proxy funktioniert es nicht, da postMessage erforderlich ist , damit MessageChannel funktioniert (zumindest in jeder Demo, die ich gesehen habe). Wenn mir nicht jemand eine Demo von MessageChannel zeigt, die ohne postMessage oder postMessage ('name', '<domain>', [messageChannel.port2]) domänenübergreifend funktioniert (ich konnte es nicht zum Laufen bringen), werde ich das nicht glauben funktioniert ohne Proxy-Frame.
Akrikos
30

Erstellen Sie eine Proxyseite auf demselben Host wie Launcher. Auf der Proxyseite ist eine iframeQuelle auf die Remote-Seite eingestellt. Ursprungsübergreifende postMessage funktioniert jetzt in IE10 wie folgt:

  • Remote-Seite wird verwendet window.parent.postMessage, um Daten an die Proxy-Seite zu übergeben. Da dies Iframes verwendet, wird es von IE10 unterstützt
  • Die Proxyseite wird verwendet window.opener.postMessage, um Daten an die Startseite zurückzugeben. Da dies auf derselben Domain liegt, gibt es keine Probleme zwischen verschiedenen Ursprüngen. Es kann auch direkt globale Methoden auf der Startseite aufrufen, wenn Sie postMessage nicht verwenden möchten - z.window.opener.someMethod(data)

Beispiel (alle URLs sind fiktiv)

Launcher-Seite bei 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>

Proxy-Seite bei 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>

Remote-Seite bei 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
quelle
Ihre Antwort wäre besser, wenn sie einen Link zur Microsoft-Beispielseite und zur Problemumgehungsseite enthalten würde, auf die in anderen Antworten verwiesen wird. Problemumgehung: blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Beispiel (von der Problemumgehungsseite
Akrikos
Außerdem verweist Ihre Beispielseite jetzt auf eine nicht gefundene Godaddy-Seite.
Akrikos
8
huh? ... alle URLs sind BEISPIELE und sollen nicht auf vorhandene Seiten verweisen ... Aus der aufgelisteten Quelle können Sie bestimmen, was getan werden muss, damit es funktioniert.
LyphTEC
Danke für die Klarstellung. :-)
Akrikos
29

== ARBEITSLÖSUNG IM JAHR 2020 ohne iframe ==

Aufbauend auf der Antwort von Tangle hatte ich Erfolg in IE11 [und emulierte den IE10-Modus] mit folgendem Snippet:

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

Dann konnte ich mit einem typischen postMessage-Stack kommunizieren. In meinem Szenario verwende ich einen globalen statischen Messenger (obwohl ich nicht annehme, dass dies von Bedeutung ist, füge ich auch meine Messenger-Klasse hinzu).

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

Egal wie sehr ich es auch versuchte, ich war nicht in der Lage, Dinge auf IE9 und IE8 zum Laufen zu bringen

Meine Konfiguration, wo es funktioniert:
IE-Version: 11.0.10240.16590, Update-Versionen: 11.0.25 (KB3100773)

Bruno Laurinec
quelle
6
Ich muss nur sagen - falls sich jemand diese Problemumgehung ansieht und denkt "auf keinen Fall, das könnte es unmöglich beheben" - ja, es hat tatsächlich die Unfähigkeit behoben, eine Nachricht an den window.opener in IE11 zu senden. Unglaublich.
dkr88
1
Auf keinen Fall ... Ich war wie 2 Tage im Versuch und dies "löst" das Problem
lmiguelmh
wirkt wie Zauber und geheimnisvoll !! (IE10.0.9200, win7)
Simon
Können Sie ein vollständiges Beispiel für diese Problemumgehung bereitstellen?
msm2020
Der ganze Trick sind die 3 Zeilen, die am Anfang der Lösung erwähnt wurden
Bruno Laurinec
2

Aufbauend auf den Antworten von LyphTEC und Akrikos besteht eine weitere Problemumgehung darin, eine zu erstellen <iframe> ein leeres Popup-Fenster , wodurch die Notwendigkeit einer separaten Proxy-Seite vermieden wird, da das leere Popup denselben Ursprung wie sein Öffner hat.

Launcher-Seite bei 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>

Remote-Seite bei 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>

Ich bin nicht sicher, wie fragil dies ist, aber es funktioniert in IE 11 und Firefox 40.0.3.

Gewirr
quelle
1
... und jetzt funktioniert es nicht (stiller Fehler im Popup-Fenster zur <iframe>Richtung) in IE 11 ( 11.0.9600.18036, Versionen aktualisieren 11.0.23 (KB3087038)). Möglicherweise ist das aktuelle Sicherheitsupdate ( KB3087038 ) betroffen .
Gewirr
1

Im Moment (02.09.2014) verwenden Sie am besten einen Proxy-Frame, wie im msdn-Blogbeitrag angegeben, der eine Problemumgehung für dieses Problem enthält: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-Implementierungsprobleme-in-ie8-und-später /

Hier ist das Arbeitsbeispiel: http://www.debugtheweb.com/test/xdm/origin/

Sie müssen auf Ihrer Seite einen Proxy-Frame einrichten, der denselben Ursprung wie das Popup hat. Senden Sie Informationen aus dem Popup mit an den Proxy-Frame window.opener.frames[0]. Verwenden Sie dann postMessage vom Proxy-Frame zur Hauptseite.

Akrikos
quelle
1

Bei dieser Lösung wird die Site zu den vertrauenswürdigen Sites von Internet Explore und nicht zu den lokalen Intranetsites hinzugefügt . Ich habe diese Lösung in Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 und Windows 7 SP1 / IE 10.0.9200.17148 getestet. Die Seite darf nicht in die Intranetzone aufgenommen werden .

Öffnen Sie also die Internet Explorer-Konfiguration (Extras> Internetoptionen> Sicherheit> Vertrauenswürdige Sites> Sites) und fügen Sie die Seite hinzu. Hier verwende ich *, um alle Subdomains abzugleichen. Stellen Sie sicher, dass die Seite nicht in den lokalen Intranetsites aufgeführt ist (Extras> Internetoptionen> Sicherheit> Lokales Intranet> Sites> Erweitert). Starten Sie Ihren Browser neu und testen Sie erneut.

Zu vertrauenswürdigen Sites in Internet Explorer hinzufügen

In Windows 10 / Microsoft Edge finden Sie diese Konfiguration unter Systemsteuerung> Internetoptionen.

AKTUALISIEREN

Wenn dies nicht funktioniert, können Sie versuchen, alle Einstellungen unter Extras> Internetoptionen> Erweiterte Einstellungen> Internet Explorer-Einstellungen zurücksetzen und dann zurücksetzen zurückzusetzen : Verwenden Sie diese Option mit Vorsicht ! Dann müssen Sie Ihr System neu starten. Fügen Sie danach die Sites zu den vertrauenswürdigen Sites hinzu.

Sehen Sie in Datei> Eigenschaften oder mit einem Rechtsklick, in welcher Zone sich Ihre Seite befindet.

Seiteneigenschaften im Internet Explorer

AKTUALISIEREN

Ich bin in einem Unternehmens-Intranet und manchmal funktioniert es und manchmal nicht (automatische Konfiguration? Ich habe sogar angefangen, dem Unternehmens-Proxy die Schuld zu geben). Am Ende habe ich diese Lösung https://stackoverflow.com/a/36630058/2692914 verwendet .

lmiguelmh
quelle
0

Dieses Q ist alt, aber dafür ist easyXDM gedacht. Überprüfen Sie es möglicherweise als möglichen Fallback, wenn Sie einen Browser erkennen, der HTML5 nicht unterstützt .postMessage:

https://easyxdm.net/

Es verwendet den VBObject-Wrapper und alle Arten von Dingen, mit denen Sie sich niemals befassen müssten, um domänenübergreifende Nachrichten zwischen Fenstern oder Frames zu senden, bei denen window.postMessage für verschiedene IE-Versionen fehlschlägt (und Edge möglicherweise immer noch nicht 100% sicher ist, was die Unterstützung betrifft Edge hat, aber es scheint auch eine Problemumgehung für .postMessage zu benötigen.

OG Sean
quelle
-3

MessageChannel funktioniert nicht für IE 9-11 zwischen Fenstern / Registerkarten, da es auf postMessage basiert, das in diesem Szenario immer noch fehlerhaft ist. Die "beste" Problemumgehung besteht darin, eine Funktion über window.opener (dh window.opener.somefunction ("somedata")) aufzurufen.

Problemumgehung hier detaillierter

user1337489
quelle
1
Dies funktioniert nicht in Cross-Origin-Einstellungen, was eine der Voraussetzungen in der Frage ist.
PhistucK