web-dev-qa-db-ja.com

IE11でpostMessageがまだ壊れていますか?

Window.postMessageは、メッセージがIE 11

  • window.openを使用したウィンドウと子ポップアップ/タブの間
  • 異なるドメインから送信された場合[または場合によっては同じドメイン、c.f。アップデート16/01]

IE 8/9/10で同様の問題がありましたが、この機能にはIE 11の「部分的にサポート」からIE 10

IEではなくchrome/ffで動作するコードの例があります。

opener(jsfiddle)

$(document).ready(function() {
    $('#log').append('listening...');
    window.addEventListener("message", function(e){
        $('#log').append("Received message: " + JSON.stringify(e.data));
    }, false);
    $('button').click(function() {
        window.open('http://jsbin.com/eQeSeros/1', 'popup','menubar=no, status=no, scrollbars=no, menubar=no, width=200, height=100');
    });
});

child popup(jsbin) :(jsfiddleで開かないと動作しません)

$(document).ready(function() {
   $('body').append('sending...');
   window.opener.postMessage("Hello?", "http://fiddle.jshell.net");
   $('body').append('sent...');
});

私は投稿から読みました IE10でクロスオリジンpostMessageは壊れていますか?MessageChannelの代わりにpostMessageを使用できますが、ドキュメントを読んで、見つけられませんでしたポートを子ウィンドウに渡す必要があるため、私の実際のケースでそれを使用する方法。

メッセージを送信する必要がある前にリダイレクトチェーンがあるため、ポートを送信できたとしても、最初/リダイレクト前に送信されたjsオブジェクトは失われます。

交換のアイデアはありますか?

Update 14/01:私はウィンドウ/タブのタイトルにデータを渡し、親からこのタイトルを定期的にチェックすることを考えています...かなり汚いトリックです。

Update 16/01:本当に悪い部分は、メッセージが同じドメインから送信されても​​、別のドメインによってリダイレクトされた後でも壊れないことです。

以下に例を示します。 http://jsfiddle.net/L4YzG/13/ ポップアップを開きます http://jsbin.com/eQeSeros/4/edit にリダイレクトします http://jsfiddle.net/mxS8Q/2/ (メッセージを投稿する)

最終的なURLリダイレクトによって直接URLポップアップを http://jsfiddle.net/mxS8Q/2/show に変更すると、IEオープニングとポストの間の他のドメイン

私はまだウィンドウタイトルのダーティトリックに取り組んでいます。別のドメインにあるウィンドウのタイトルを受け取ることはできませんが、jsfiddleに戻った場合、タイトルは利用可能です(postMessageには以前の問題はありません)。以下に例を示します。 http://jsfiddle.net/L4YzG/14/ ...これは代替ソリューションかもしれませんが、Cookieでデータを渡すことについて何かを見ました。テストされる。

更新04/02:タイトルに情報を渡すだけでは十分ではありません。最終ドメインが同じでもクロスドメインにない場合はうまく機能します。これらの情報を渡すために同じドメインのiframeを挿入したかったのですが、子ウィンドウオブジェクトも共有できません(postMessageにはシリアル化可能なオブジェクトが必要です)。

最後に、注入されたiframeと子ウィンドウ間でcookie(jsで作成および受信)を共有しようとしました。これはchrome&ffでうまく機能しますが、IEで正しく受信できませんでした。 P3Pヘッダーは問題なく機能しており、これが真の解決策のようです。Safariはこの手法に問題があるようで、この手法をフォールバックとして保持します。

25
bumpmann

更新16/01:本当に悪い部分は、メッセージが同じドメインから送信されても​​、別のドメインによってリダイレクトされた後でも壊れないことです。

陽気なことに、この「セキュリティ機能」を逆に使用して、クロスドメインの制限を完全にバイパスすることができます。

親ウィンドウのexample.com

<script>
  window.open("http://example.com/dummy_redirect");
  window.addEventListener('message', function(ev) {console.log(ev.data)})
</script>

オン example.comサーバー:

GET /dummy_redirect 302 http://jsfiddle.net/b6yfbunw/

ドメインに対してポップアップが開き、jsfiddleにリダイレクトされ、IEでpostMessage呼び出しが機能します。その後、任意のドメインに移動して、引き続き親ウィンドウへのpostMessage呼び出しを行うこともできます。

15
Neil Sarkar

壊れていますか?まあ、ちょっと。

さまざまなアイデアを試しましたが、 jsFiddle のコードを動作させることができませんでした。これを見ると MSDNブログの投稿 で、postMessageはIEの古いバージョンのIFrameの間でのみ機能することがわかります。これはIE 11でまだ修正されていません。

その記事は、問題の デモ にリンクしています。 window.openerでスクリプトを呼び出すことを伴う回避策がいくつかあります。しかし、そのブログが述べているように(強調鉱山):

残念ながら、この回避策は多くの場合不可能です。same-Origin-policyは、ポップアップウィンドウとwindow.openerページが同じOrigin互いのスクリプト関数を呼び出すため。

そのため、これを行う唯一の方法は this のようなもので、子は親のIFrameでホストされているように見えます。あなたのコードに基づいて、同様のデモ here を作成しました。とても簡単ですが、メッセージをIFrameのcontentWindowに投稿し、それが応答します。

代わりにMessageChannelを使用することをお勧めしますが、 Web Workers を使用することは調査する価値があるかもしれませんが、その使用はもちろんタスクの性質に依存します。これに対する答えもあります question 、IFrameアプローチが使用されましたが、jQuery UIダイアログを使用してそれを表示しました-Bootstrapそれを好むなら。


参考のために:

[〜#〜] html [〜#〜]

<iframe id="iframe" src="http://jsbin.com/iLapokOS/7/"></iframe>
<div id="log"></div>
<button id="post-message-button">Post message to window</button>

親スクリプト

var wnd;

$(document).ready(function() {
    $('#log').append('listening...');

    wnd = $('#iframe')[0].contentWindow;

    window.addEventListener('message', function(e){
      $('#log').append('<br/>Received message: ' + JSON.stringify(e.data));
    }, false);

    $('#post-message-button').click(function() {
        if(!wnd){
            return;
        }
        $('#log').append('<br/>sending...');
        wnd.postMessage('Hello?', 'http://jsbin.com');
    });
});

子HTMLおよびJS

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <script>
    $(document).ready(function() {

      window.addEventListener("message", function(e){
        $('body').append('<br/>Origin: ' + e.Origin);        
        $('body').append("<br/>Received message: " + JSON.stringify(e.data));

        e.source.postMessage('Hello yourself', e.Origin);
      }, false);
    });
  </script>


</body>
</html>
14
nick_w

iframeの回避策についてはいくつか言及されていますが、私が見たのはsendingiframe

代わりにiframeからメッセージを受信するreceiveの例を次に示します。

親ページ(http://first-domain.com/receive-message.html)

<html>
  <head>
    <script>
      window.addEventListener('message', console.log.bind(console, 'Got message:'));
    </script>
  </head>
  <body>
    <iframe src="http://second-domain.com/send-message.html"></iframe>
  </body>
</html>

子ページ(http://second-domain.com/send-message.html)

<html>
  <head>
    <script>
      window.parent.postMessage('hi there', '*');
    </script>
  </head>
  <body></body>
</html>
4
c24w

別のウィンドウを起動し、ウィンドウを起動してから別のウィンドウを閉じると、ウィンドウを正常に操作できることがわかりました。

vvWindow0 = window.open("http://apsed4065:8047/virtualviewer/index.html");
vvWindow = window.open("http://apsed4065:8047/virtualviewer/index.html");
vvWindow0.close(); <!-- to close the window -->

vvWindow.postMessage(message, 'http://apsed4065:8047');