Чи порушено повідомлення про похідне повідомлення в IE10?


91

Я намагаюся змусити банальний postMessageприклад працювати ...

  • в IE10
  • між вікнами / вкладками (проти iframes)
  • за походженням

Видаліть будь-яку з цих умов, і все працює нормально :-)

Але, наскільки я можу зрозуміти, між вікнами, postMessageздається, працює лише в IE10, коли обидва вікна мають спільне походження. (Ну, насправді - і дивно - поведінка трохи більш дозвільна, ніж така: здається, теж працюють два різних походження, які мають спільного хоста ).

Це задокументована помилка? Будь-які обхідні шляхи чи інші поради?

(Примітка: Це питання торкається питань, але його відповідь стосується IE8 та IE9 - не 10)


Детальніше + приклад ...

демо запуску сторінки -

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

запущена демонстрація сторінки

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

Це працює за адресою: http://jsbin.com/ahuzir/1 - оскільки обидві сторінки розміщені в одному джерелі (jsbin.com). Але перемістіть другу сторінку куди завгодно, і це не вдається в IE10.



5
Будь ласка, подумайте про те, щоб змінити прийняту відповідь на таку, яка відповідає на питання, а не на таку, яка перелічує MessageChannel як найкращий вибір, коли MessageChannel вимагає postMessage, щоб він працював. Я витратив більше години, граючись із MessageChannel, лише щоб виявити, що єдиним життєздатним рішенням є проксі-сервер iframe.
Акрікос

1
Якщо ваш window.open - це лише спливаюче діалогове вікно, ви можете взагалі його уникнути і використовувати iframe у js-модалі. Щось на зразок jQuery Dialog або Bootstrap Modal - це те, як я це реалізував. Тоді ви можете використовувати window.parent.postMessageв IE.
styfle

@Bosh, оскільки моя відповідь, здається, працює в 2018 році і не вимагає проксі-кадру, не могли б ви встановити це як прийняту відповідь, оскільки це, здається, допомагає нам, нещасним, котрі все ще повинні підтримувати стару, тобто
Бруно Лаурінець

Відповіді:


62

Я помилився, коли спочатку розмістив цю відповідь: це насправді не працює в IE10. Очевидно, люди знайшли це корисним з інших причин, тому я залишаю це для нащадків. Оригінальна відповідь нижче:


Варто зазначити: посилання у цій відповіді, яке ви посилали на держави, які postMessageне мають перехресного походження для окремих вікон в IE8 та IE9 - однак воно також було написане в 2009 році, до появи IE10. Тому я б не сприймав це як ознаку того, що це виправлено в IE10.

Що стосується postMessageсамого себе, http://caniuse.com/#feat=x-doc-messaging, зокрема, вказує на те, що він все ще не працює в IE10, що, схоже, відповідає вашій демонстрації. Сторінка caniuse посилається на цю статтю , яка містить дуже актуальну цитату:

Internet Explorer 8+ частково підтримує обмін повідомленнями між документами: наразі він працює з iframes, але не з новими вікнами. Однак Internet Explorer 10 підтримуватиме MessageChannel. Наразі Firefox підтримує обмін повідомленнями між документами, але не MessageChannel.

Отже, найкращим варіантом є, мабуть, наявність MessageChannelкодового шляху на основі, а також резервний варіант, postMessageякщо такого не існує. Ви не отримаєте підтримку IE8 / IE9, але принаймні це буде працювати з IE10.

Документи на MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx


8
Як би ви створили MessageChannelкодовий шлях на основі, який працює? Вам все ще потрібно функціонувати, postMessageщоб перевести порт каналу в інше вікно.
balpha

1
Використання postMessageз новим MessageChannelAPI буде працювати в нових вікнах та джерелах. Напевно, робота трохи незручна, але в основному: postMessage('foo', '*')погано, postMessage('foo', [messageChannel.port2])добре.
ShZ

3
Я не можу протягом усього життя отримати postMessage, працюючи з міждоменним спливаючим вікном, використовуючи останню версію IE (11) та MessageChannel API. І чесно кажучи, я не можу знайти ніде більше на Інтернеті, крім цієї відповіді, яка вказує на те, що цей конкретний сценарій повинен спрацювати. Хтось може вказати на приклад, що доводить, що це працює? Буду вічно вдячний.
Тодд Меньє

4
MessageChannel не повинен працювати з тієї ж причини, чому postMessage не буде. Корпорація Майкрософт потребує виправлення перебігу міжпроцесорних процесів. blogs.msdn.com/b/ieinternals/archive/2009/09/15/…
EricLaw 02

9
Ця відповідь дратує, бо дає нам помилкову надію. Відповідь така: він не буде працювати без проксі-сервера, оскільки postMessage потрібен, щоб MessageChannel працював (принаймні у кожному демонстраційному файлі, який я бачив). Якщо хтось не покаже мені демонстраційну версію MessageChannel, яка працює без postMessage або postMessage ('name', '<domain>', [messageChannel.port2]), що працює міждоменного (я не міг змусити його працювати), я не повірю в це працює без проксі-кадру.
Акрикос,

30

Створіть проксі-сторінку на тому ж хості, що і панель запуску. Сторінка проксі має iframeвихідну сторінку з віддаленою сторінкою. PostMessage з перехресним походженням тепер працюватиме в IE10 так:

  • Віддалена сторінка використовує window.parent.postMessageдля передачі даних на проксі-сторінку. Оскільки для цього використовуються фрейми, це підтримується IE10
  • Проксі-сторінка використовує window.opener.postMessageдля передачі даних назад на сторінку запуску. Оскільки це в одному домені - проблем із перехресним походженням немає. Він також може безпосередньо викликати глобальні методи на сторінці запуску, якщо ви не хочете використовувати postMessage - наприклад.window.opener.someMethod(data)

Зразок (усі URL-адреси є фіктивними)

Сторінка запуску за адресою 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>

Проксі-сторінка за адресою 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>

Віддалена сторінка за адресою 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>

Ваша відповідь була б кращою, якби вона містила посилання на прикладну сторінку Майкрософт та сторінку обхідного шляху, на яку посилаються інші відповіді. Обхідний шлях : blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Приклад (зі сторінки обхідного шляху
Акрікос,

Крім того, ваша прикладна сторінка тепер посилається на сторінку godaddy, яку не знайдено.
Акрикос,

8
так? ... всі URL-адреси - ПРИКЛАДИ і не призначені для того, щоб насправді вказувати на існуючі сторінки ... із перерахованого джерела ви можете визначити, що потрібно зробити, щоб це запрацювало ..
LyphTEC

Дякую за роз'яснення. :-)
Акрікос

29

== РОБОЧЕ РІШЕННЯ У 2020 р. Без iframe ==

Спираючись на відповідь клубок, я мав успіх в IE11 [і емулював режим IE10], використовуючи такий фрагмент:

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

Тоді я зміг спілкуватися, використовуючи типовий стек postMessage, я використовую один глобальний статичний месенджер у своєму сценарії (хоча я не думаю, що це має якесь значення, я також додаю свій клас месенджера)

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

Як би я не старався, я не зміг змусити речі працювати на IE9 та IE8

Мій конфігуратор, де він працює:
IE версія: 11.0.10240.16590, версії оновлення: 11.0.25 (KB3100773)


6
Мені просто потрібно сказати - на випадок, якщо хтось ще дивиться на цей обхідний шлях, думаючи "ніяк, це не могло б це виправити" - так, це насправді виправило неможливість postMessage на window.opener в IE11. Неймовірно.
dkr88,

1
Ні в якому разі ... Я як 2 дні намагався, і це "вирішило" проблему
lmiguelmh

працює як обереги та загадкові !! (IE10.0.9200, win7)
Саймон

Чи можете ви надати повний приклад цього обхідного шляху?
msm2020

1
@SidJonnala не дуже, але я б рекомендував це. Якщо ви негайно перепризначите фактичну віддалену сторінку, і ваша сторінка завантажиться через 3-4 секунди [це може траплятися час від часу], тоді ви ризикуєте, що ваша сторінка window.open ('/') завантажиться і заплутає користувача
Бруно Лаурінек,

2

Спираючись на відповіді LyphTEC та Akrikos, ще одним робочим завданням є створення <iframe>всередині порожнього спливаючого вікна, що дозволяє уникнути потреби в окремій проксі-сторінці, оскільки пусте спливаюче вікно має те саме походження, що і його відкривач.

Сторінка запуску за адресою 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>

Віддалена сторінка за адресою 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>

Я не впевнений, наскільки це тендітно, але це працює в IE 11 та Firefox 40.0.3.


1
... і тепер це не працює (тихий збій у спливаючому вікні в <iframe>напрямку) в IE 11 ( 11.0.9600.18036, версії оновлення 11.0.23 (KB3087038)). Можливо, нещодавнє оновлення безпеки ( KB3087038 ) має відношення.
клубок

1

Зараз, (02.09.2014), найкращим є використання проксі-кадру, як зазначено у дописі блогу msdn, де описано обхідний шлях для вирішення цієї проблеми: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-Implementation-issues-in-ie8-і пізніше /

Ось робочий приклад: http://www.debugtheweb.com/test/xdm/origin/

Вам потрібно встановити проксі-кадр на вашій сторінці, який має те саме походження, що і спливаюче вікно. Надішліть інформацію зі спливаючого вікна до проксі-кадру за допомогою window.opener.frames[0]. Потім використовуйте postMessage з проксі-кадру на головну сторінку.


1

Це рішення передбачає додавання сайту до довірених сайтів Internet Explorer, а не на сайтах локальної інтрамережі. Я тестував це рішення в Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 та Windows 7 SP1 / IE 10.0.9200.17148. Сторінка не повинна бути включена в Інтранет-зону .

Тож відкрийте конфігурацію Internet Explorer (Інструменти> Властивості браузера> Безпека> Довірені сайти> Сайти) і додайте сторінку, тут я використовую * для відповідності всіх субдоменів. Переконайтесь, що сторінки немає в списку на сайтах локальної інтрамережі (Інструменти> Властивості браузера> Безпека> Локальна інтранет> Сайти> Додатково). Перезапустіть браузер і протестуйте ще раз.

Додайте до надійних сайтів в Internet Explorer

У Windows 10 / Microsoft Edge ви знайдете цю конфігурацію в Панелі керування> Властивості браузера.

ОНОВЛЕННЯ

Якщо це не спрацює, спробуйте скинути всі налаштування в меню Інструменти> Властивості браузера> Додаткові налаштування> Скинути налаштування Internet Explorer, а потім Скинути: використовуйте його з обережністю ! Тоді вам потрібно буде перезавантажити систему. Після цього додайте сайти до надійних сайтів.

Подивіться, в якій зоні знаходиться ваша сторінка, у меню Файл> Властивості або клацнувши правою кнопкою миші.

Властивості сторінки в Internet Explorer

ОНОВЛЕННЯ

Я перебуваю в корпоративній інтрамережі, і іноді це працює, а іноді ні (автоматична конфігурація? Я навіть почав звинувачувати корпоративного проксі). Врешті-решт я використав це рішення https://stackoverflow.com/a/36630058/2692914 .


0

Це Q старе, але саме для цього призначений easyXDM, можливо, перевірити його як потенційний резервний варіант, коли виявите браузер, який не підтримує html5 .postMessage:

https://easyxdm.net/

Він використовує обгортку VBObject та всі типи речей, з якими вам ніколи не доведеться мати справу, щоб надсилати міждоменні повідомлення між вікнами або фреймами, де window.postMessage виходить з ладу для різних версій IE (і, можливо, все ще не впевнений на 100% у підтримці Edge має, але, схоже, йому також потрібен обхідний шлях для .postMessage)


-3

MessageChannel не працює для IE 9-11 між вікнами / вкладками, оскільки він покладається на postMessage, який у цьому сценарії все ще не працює. Найкращим обхідним шляхом є виклик функції через window.opener (тобто window.opener.somefunction ("somedata")).

Тут можна детальніше обійти цю проблему


1
Це не працює в налаштуваннях перехресного походження, що є однією з необхідних умов у питанні.
PhistucK
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.