web-dev-qa-db-ja.com

IE10でクロスオリジンのpostMessageが壊れていますか?

些細なpostMessageサンプルを機能させようとしています...

  • iE10で
  • ウィンドウ/タブ間(vs. iframes)
  • 起源を越えて

これらの条件のいずれかを削除すると、問題なく動作します:-)

しかし、私が知る限り、inter-window postMessageは、両方のウィンドウがOriginを共有している場合にのみIE10で機能するように見えます。 (まあ、実際、奇妙なことに、動作はそれよりも少し寛容です:Hostを共有する2つの異なる起源も機能するようです)。

これは文書化されたバグですか?回避策やその他のアドバイスはありますか?

(注: この質問 問題に触れますが、 その答え は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 -両方のページが同じOrigin(jsbin.com)でホストされているためです。しかし、2番目のページを他の場所に移動すると、IE10で失敗します。

89
Bosh

私がこの回答を最初に投稿したとき、私は間違っていました:IE10では実際には動作しません。どうやらこれは他の理由で有用であることがわかっているので、後世のために残しています。以下の元の回答:


注目に値する:あなたがリンクした回答のリンクは、postMessageがIE8とIE9の別々のウィンドウのOriginを超えていないことを示しています-しかし、IE10が登場する前の2009年にも書かれました。ですから、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

61
ShZ

ランチャーと同じホストにプロキシページを作成します。プロキシページには、ソースがリモートページに設定されたiframeがあります。 Cross-Origin postMessageはIE10で次のように機能するようになりました。

  • リモートページは、window.parent.postMessageを使用してデータをプロキシページに渡します。これはiframeを使用するため、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>
30
LyphTEC

もつれによる答えに基づいて、私は次のスニペットを使用してIE11 [およびエミュレートされたIE10モード]で成功しました:

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

それから、典型的なpostMessageスタックを使用して通信できました。シナリオでは1つのグローバルな静的メッセンジャーを使用しています(重要性はないと思いますが、メッセンジャークラスも添付します)

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)

23
Bruno Laurinec

LyphTECとAkrikosの回答に基づいて、別の回避策は、空白のポップアップウィンドウ内に<iframe>を作成することです。空白のポップアップはオープナーと同じOriginを持っているので、別のプロキシページは必要ありません。

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で動作しています。

2
tangle

現在(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/

ポップアップと同じOriginを持つプロキシフレームをページに設定する必要があります。 window.opener.frames[0]を使用して、ポップアップからプロキシフレームに情報を送信します。次に、プロキシフレームからメインページへのpostMessageを使用します。

1
Akrikos

このソリューションでは、サイトをInternet Exploreの信頼済みサイトに追加し、ローカルイントラネットサイトに not を追加します。このソリューションは、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の構成([ツール]> [インターネットオプション]> [セキュリティ]> [信頼済みサイト]> [サイト])を開き、ページを追加します。ここでは、*を使用してすべてのサブドメインを一致させます。 ローカルイントラネットサイトにリストされているページis n'tを確認します([ツール]> [インターネットオプション]> [セキュリティ]> [ローカルイントラネット]> [サイト]> [詳細])。もう一度テストします。

Add to trusted sites in Internet Explorer

Windows 10/Microsoft Edgeでは、この設定は[コントロールパネル]> [インターネットオプション]にあります。

UPDATE

これが機能しない場合は、ツール>インターネットオプション>詳細設定> Internet Explorerの設定をリセットですべての設定をリセットしてから、リセットしてみてください:注意!その後、システムを再起動する必要があります。その後、信頼済みサイトにサイトを追加します。

[ファイル]> [プロパティ]または右クリックを使用して、ページがどのゾーンにあるかを確認します。

Page properties in internet Explorer

UPDATE

私は企業のイントラネットにいますが、時には機能しますが、時には機能しません(自動構成?企業のプロキシを非難し始めました)。最終的に私はこのソリューションを使用しました https://stackoverflow.com/a/36630058/2692914

1
lmiguelmh