Próbuję sprawić, by trywialny postMessage
przykład zadziałał ...
- w IE10
- między oknami / kartami (w porównaniu z ramkami iframe)
- z różnych źródeł
Usuń jeden z tych warunków i wszystko działa dobrze :-)
Ale o ile wiem, między oknami postMessage
wydaje się działać tylko w IE10, gdy oba okna mają wspólne źródło. (Cóż, w rzeczywistości - i co dziwne - zachowanie jest nieco bardziej pobłażliwe: dwa różne źródła, które współdzielą hosta, też wydają się działać).
Czy to udokumentowany błąd? Jakieś obejścia lub inne porady?
(Uwaga: to pytanie dotyka problemów, ale odpowiedź dotyczy IE8 i IE9 - nie 10)
Więcej szczegółów + przykład ...
Demo strony uruchamiania
<!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>
uruchomiono demo strony
<!DOCTYPE html>
<html>
<script>
window.opener.postMessage("Ahoy!", "*");
</script>
</html>
Działa to pod adresem: http://jsbin.com/ahuzir/1 - ponieważ obie strony są hostowane w tym samym miejscu pochodzenia (jsbin.com). Ale przenieś drugą stronę gdziekolwiek indziej, aw IE10 nie działa.
window.parent.postMessage
w IE.Odpowiedzi:
Pomyliłem się, kiedy pierwotnie opublikowałem tę odpowiedź: tak naprawdę nie działa w IE10. Najwyraźniej ludzie uznali to za przydatne z innych powodów, więc zostawiam to potomności. Oryginalna odpowiedź poniżej:
Warto zauważyć: odsyłacz w tej odpowiedzi łączył się ze stanami, które
postMessage
nie są krzyżowe dla oddzielnych okien w IE8 i IE9 - jednak został również napisany w 2009 r., Zanim pojawił się IE10. Więc nie wziąłbym tego jako wskazówkę, że jest to naprawione w IE10.Jeśli chodzi o
postMessage
siebie, http://caniuse.com/#feat=x-doc-messaging w szczególności wskazuje, że nadal jest uszkodzony w IE10, który wydaje się pasować do twojego demo. Strona caniuse prowadzi do tego artykułu , który zawiera bardzo trafny cytat:Więc najlepszym rozwiązaniem jest prawdopodobnie posiadanie
MessageChannel
ścieżki kodowej opartej na kodach i powrót do niej,postMessage
jeśli ona nie istnieje. Nie zapewni ci obsługi IE8 / IE9, ale przynajmniej będzie działać z IE10.Dokumenty na
MessageChannel
: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspxźródło
MessageChannel
ścieżkę kodową? Nadal musisz działać,postMessage
aby przenieść port kanału do innego okna.postMessage
z nowymMessageChannel
interfejsem API będzie działać w nowych oknach i źródłach. Wydaje mi się, że praca jest trochę niezręczna, ale w zasadzie:postMessage('foo', '*')
jest zła,postMessage('foo', [messageChannel.port2])
jest dobra.Utwórz stronę proxy na tym samym hoście, co program uruchamiający. Strona proxy ma
iframe
ze źródłem ustawionym na stronę zdalną. PostMessage z innych źródeł będzie teraz działać w IE10 w następujący sposób:window.parent.postMessage
do przekazywania danych do strony proxy. Ponieważ używa ramek iframe, jest obsługiwany przez IE10window.opener.postMessage
do przekazywania danych z powrotem na stronę programu uruchamiającego. Ponieważ jest to w tej samej domenie - nie ma problemów związanych z różnymi źródłami. Może również bezpośrednio wywoływać globalne metody na stronie programu uruchamiającego, jeśli nie chcesz używać postMessage - np.window.opener.someMethod(data)
Przykład (wszystkie adresy URL są fikcyjne)
Strona uruchamiania pod adresem
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>
Strona proxy pod adresem
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>
Strona zdalna pod adresem
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>
źródło
== ROZWIĄZANIE PRACY W 2020 ROKU bez iframe ==
Opierając się na odpowiedzi przez plątaninę, odniosłem sukces w IE11 [i emulowanym trybie IE10], używając następującego fragmentu kodu:
var submitWindow = window.open("/", "processingWindow"); submitWindow.location.href = 'about:blank'; submitWindow.location.href = 'remotePage to comunicate with';
Potem mogłem komunikować się za pomocą typowego stosu postMessage, w moim scenariuszu używam jednego globalnego statycznego komunikatora (choć nie przypuszczam, że ma to jakiekolwiek znaczenie, dołączam również moją klasę komunikatora)
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; } }
Bez względu na to, jak bardzo się starałem, nie mogłem sprawić, by wszystko działało na IE9 i IE8
Moja konfiguracja, gdzie działa:
wersja IE: 11.0.10240.16590, wersje aktualizacji: 11.0.25 (KB3100773)
źródło
Opierając się na odpowiedziach LyphTEC i Akrikos, innym obejściem jest utworzenie
<iframe>
w pustym wyskakującym okienku, co pozwala uniknąć potrzeby oddzielnej strony proxy, ponieważ puste okienko ma to samo źródło co otwieracz.Strona uruchamiania pod adresem
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>
Strona zdalna pod adresem
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>
Nie jestem pewien, jak delikatne jest to, ale działa w IE 11 i Firefox 40.0.3.
źródło
<iframe>
kierunku) w IE 11 (11.0.9600.18036
aktualizacja wersji11.0.23 (KB3087038)
). Prawdopodobnie chodzi o ostatnią aktualizację zabezpieczeń ( KB3087038 ).W tej chwili (02.09.2014) najlepszym rozwiązaniem jest użycie ramki proxy, jak wspomniano w poście na blogu msdn, który szczegółowo opisuje obejście tego problemu: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-Implementation Issues-in-ie8-and-later /
Oto działający przykład: http://www.debugtheweb.com/test/xdm/origin/
Musisz ustawić ramkę proxy na swojej stronie, która ma to samo źródło co wyskakujące okienko. Wyślij informacje z wyskakującego okienka do ramki proxy za pomocą
window.opener.frames[0]
. Następnie użyj postMessage z ramki proxy do strony głównej.źródło
To rozwiązanie polega na dodaniu witryny do zaufanych witryn programu Internet Explorer, a nie do witryn w lokalnym intranecie. Testowałem to rozwiązanie w Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 i Windows 7 SP1 / IE 10.0.9200.17148. Strona nie może znajdować się w strefie intranetu .
Otwórz więc konfigurację Internet Explorera (Narzędzia> Opcje internetowe> Zabezpieczenia> Zaufane witryny> Witryny) i dodaj stronę, tutaj używam * do dopasowania wszystkich subdomen. Upewnij się, że strona nie jest wyświetlana w lokalnych witrynach intranetowych (Narzędzia> Opcje internetowe> Zabezpieczenia> Lokalny intranet> Witryny> Zaawansowane). Uruchom ponownie przeglądarkę i ponownie przetestuj.
W systemie Windows 10 / Microsoft Edge tę konfigurację znajdziesz w Panelu sterowania> Opcje internetowe.
AKTUALIZACJA
Jeśli to nie zadziała, możesz spróbować zresetować wszystkie ustawienia w menu Narzędzia> Opcje internetowe> Ustawienia zaawansowane> Zresetuj ustawienia programu Internet Explorer, a następnie Resetuj: używaj go ostrożnie ! Następnie musisz ponownie uruchomić system. Następnie dodaj witryny do zaufanych witryn.
Zobacz, w której strefie znajduje się Twoja strona w Plik> Właściwości lub klikając prawym przyciskiem myszy.
AKTUALIZACJA
Jestem w firmowym intranecie i czasami to działa, a czasami nie (automatyczna konfiguracja? Zacząłem nawet obwiniać korporacyjny serwer proxy). W końcu skorzystałem z tego rozwiązania https://stackoverflow.com/a/36630058/2692914 .
źródło
Ta Q jest stara, ale do tego właśnie służy easyXDM. Może sprawdź ją jako potencjalną rezerwę, gdy wykryjesz przeglądarkę, która nie obsługuje html5 .postMessage:
https://easyxdm.net/
Używa opakowania VBObject i wszystkich rodzajów rzeczy, z którymi nigdy nie chciałbyś mieć do czynienia, aby wysyłać wiadomości między domenami między oknami lub ramkami, w których window.postMessage nie działa dla różnych wersji IE (i być może krawędzi, nadal nie jestem pewien 100% wsparcia) Edge ma, ale wydaje się, że potrzebuje również obejścia dla .postMessage)
źródło
MessageChannel nie działa w IE 9-11 między oknami / kartami, ponieważ opiera się na postMessage, który nadal jest uszkodzony w tym scenariuszu. „Najlepszym” obejściem jest wywołanie funkcji przez window.opener (np. Window.opener.somefunction („somedata”)).
Więcej szczegółów obejścia tutaj
źródło