Является ли перекрестное происхождение postMessage сломанным в IE10?

Я пытаюсь сделать тривиальный пример postMessage...

  • в IE10
  • между окнами/вкладками (по сравнению с iframe)
  • по происхождению

Удалите любое из этих условий, и все будет работать нормально: -)

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

Является ли это документированной ошибкой? Любые обходные пути или другие рекомендации?

(Примечание: Этот вопрос затрагивает проблемы, но его ответ касается IE8 и IE9 - - не 10)


Подробнее + пример...

страница запуска demo

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

запущена страница demo

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

Это работает по адресу http://jsbin.com/ahuzir/1 - поскольку обе страницы размещены в одном месте (jsbin.com). Но переместите вторую страницу где-нибудь еще, и она не работает в IE10.

Ответ 1

Я ошибся, когда я изначально опубликовал этот ответ: он действительно не работает в IE10.. По-видимому, люди считают это полезным по другим причинам, поэтому я оставляю его для потомков. Оригинальный ответ ниже:


Стоит отметить: ссылка в том ответе, на которую вы ссылались, указывает, что postMessage не является перекрестным происхождением для отдельных окон в IE8 и IE9, однако он также был написан в 2009 году, прежде чем появился IE10. Поэтому я не стал бы считать это признаком того, что он исправлен в IE10.

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

Internet Explorer 8+ частично поддерживает обмен сообщениями между документами: он в настоящее время работает с iframe, но не с новыми окнами. Internet Explorer 10, однако, будет поддерживать MessageChannel. Firefox в настоящее время поддерживает обмен сообщениями между документами, но не MessageChannel.

Таким образом, ваш лучший выбор - вероятно, иметь кодовую форму на основе MessageChannel и отбрасывать на postMessage, если этого не существует. Он не получит поддержку IE8/IE9, но, по крайней мере, он будет работать с IE10.

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

Ответ 2

Создайте прокси-страницу на том же хосте, что и для запуска. Страница прокси имеет iframe с источником, установленным на удаленную страницу. Cross-origin postMessage теперь будет работать в IE10 следующим образом:

  • Удаленная страница использует window.parent.postMessage для передачи данных на страницу прокси. Поскольку это использует iframes, он поддерживается 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>

Ответ 3

Основываясь на ответе путанием, я имел успех в 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)

Ответ 4

Прямо сейчас, (2014-09-02), лучше всего использовать прокси-фрейм, как указано в сообщении блога msdn, в котором описывается обходной путь для этой проблемы: https://blogs.msdn.microsoft.com/ieinternals/2009/09/15/html5-implementation-issues-in-ie8-and-later/

Вот рабочий пример: http://www.debugtheweb.com/test/xdm/origin/

Вам нужно настроить прокси-фрейм на своей странице с тем же именем, что и всплывающее окно. Отправьте информацию из всплывающего окна в рамку прокси с помощью window.opener.frames[0]. Затем используйте postMessage из кадра прокси на главную страницу.

Ответ 5

Основываясь на ответах 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.

Ответ 6

Это решение включает в себя добавление сайта в Internet Explore Trusted Sites, а не на сайтах локальной интрасети. Я протестировал это решение в 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 ( "Сервис" > "Свойства обозревателя" > "Безопасность" > "Надежные узлы" > "Сайты" ) и добавьте страницу, здесь я использую * для соответствия всем поддоменам. Убедитесь, что страница не указана, указанная на сайтах локальной интрасети (Сервиs > Свойства обозревателя > Безопасность > Локальная интрасеть > Сайты > Дополнительно). Перезагрузите браузер и снова проверьте.

Добавить в надежные сайты в Internet Explorer

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

UPDATE

Если это не сработает, вы можете попробовать сбросить все свои настройки в меню "Сервис" > "Свойства обозревателя" > "Дополнительные параметры" > "w70", а затем "w71": использовать его с осторожностью! Затем вам нужно будет перезагрузить систему. После этого добавьте сайты в надежные сайты.

Посмотрите, в какой зоне находится ваша страница в "Файл" > "Свойства" или щелкните правой кнопкой мыши.

Свойства страницы в Internet Explorer

UPDATE

Я работаю в корпоративной интрасети, и иногда она работает, а иногда нет (автоматическая настройка? Я даже начал обвинять корпоративный прокси-сервер). В конце я использовал это решение fooobar.com/questions/72577/....

Ответ 7

MessageChannel не работает для IE 9-11 между окнами/вкладками, поскольку он полагается на postMessage, который по-прежнему не работает в этом сценарии. "Лучшим" решением является вызов функции через window.opener(например, window.opener.somefunction( "somedata" )).

Обходное решение более подробно здесь