Apakah postMessage lintas sumber rusak di IE10?

91

Saya mencoba membuat postMessagecontoh yang sepele berhasil ...

  • di IE10
  • antara jendela / tab (vs. iframe)
  • melintasi asal

Hapus salah satu dari kondisi ini, dan semuanya berfungsi dengan baik :-)

Tapi sejauh yang saya tahu, antara jendela postMessagehanya tampak berfungsi di IE10 ketika kedua jendela berbagi asal. (Sebenarnya - dan anehnya - perilakunya sedikit lebih permisif dari itu: dua asal berbeda yang berbagi host tampaknya juga berfungsi).

Apakah ini bug yang terdokumentasi? Ada solusi atau saran lain?

(Catatan: Pertanyaan ini menyentuh masalah, tetapi jawabannya tentang IE8 dan IE9 - bukan 10)


Lebih detail + contoh ...

demo halaman peluncur

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

meluncurkan demo halaman

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

Ini berfungsi di: http://jsbin.com/ahuzir/1 - karena kedua laman dihosting pada asal yang sama (jsbin.com). Tapi pindahkan halaman kedua ke tempat lain, dan itu gagal di IE10.

Omong kosong
sumber
5
Harap pertimbangkan untuk mengubah jawaban yang diterima menjadi jawaban yang menjawab pertanyaan daripada yang mencantumkan MessageChannel sebagai taruhan terbaik Anda saat MessageChannel membutuhkan postMessage untuk membuatnya berfungsi. Saya menghabiskan lebih dari satu jam bermain dengan MessageChannel hanya untuk menemukan bahwa satu solusi yang layak adalah proxy iframe.
Akrikos
1
Jika window.open Anda hanyalah dialog popup, Anda dapat menghindarinya sama sekali dan menggunakan iframe dalam modal js. Sesuatu seperti jQuery Dialog atau Bootstrap Modal adalah bagaimana saya menerapkannya. Kemudian Anda dapat menggunakannya window.parent.postMessagedi IE.
styfle
@Bosh sebagai jawaban saya tampaknya berfungsi di 2018 dan tidak memerlukan bingkai proxy, maukah Anda menetapkan itu sebagai jawaban yang diterima karena tampaknya membantu kami, yang malang yang masih harus mendukung yang lama yaitu
Bruno Laurinec

Jawaban:

62

Saya salah ketika saya awalnya memposting jawaban ini: itu tidak benar-benar berfungsi di IE10. Rupanya orang telah menemukan ini berguna untuk alasan lain jadi saya meninggalkannya untuk anak cucu. Jawaban asli di bawah ini:


Perlu dicatat: tautan dalam jawaban itu yang Anda tautkan ke status yang postMessagebukan merupakan asal silang untuk jendela terpisah di IE8 dan IE9 - namun, itu juga ditulis pada tahun 2009, sebelum IE10 muncul. Jadi saya tidak akan menganggapnya sebagai indikasi bahwa itu diperbaiki di IE10.

Sedangkan untuk postMessagedirinya sendiri, http://caniuse.com/#feat=x-doc-messaging menunjukkan bahwa itu masih rusak di IE10, yang tampaknya cocok dengan demo Anda. Halaman caniuse tertaut ke artikel ini , yang berisi kutipan yang sangat relevan:

Internet Explorer 8+ mendukung sebagian perpesanan lintas dokumen: saat ini ia berfungsi dengan iframe, tetapi bukan jendela baru. Internet Explorer 10, bagaimanapun, akan mendukung MessageChannel. Firefox saat ini mendukung perpesanan lintas dokumen, tetapi tidak mendukung MessageChannel.

Jadi taruhan terbaik Anda mungkin memiliki MessageChannelalur kode berbasis, dan mundur ke postMessagejika itu tidak ada. Ini tidak akan memberi Anda dukungan IE8 / IE9, tetapi setidaknya itu akan bekerja dengan IE10.

Dokumen di MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx

ShZ
sumber
8
Bagaimana Anda membuat jalur MessageChannelkode berbasis yang berfungsi? Anda masih perlu berfungsi postMessageuntuk mendapatkan port saluran ke jendela lain.
balpha
1
Menggunakan postMessagedengan MessageChannelAPI baru akan berfungsi di jendela dan asal baru. Pekerjaannya agak canggung, saya kira, tetapi pada dasarnya: postMessage('foo', '*')buruk, postMessage('foo', [messageChannel.port2])itu baik.
ShZ
3
Saya tidak bisa seumur hidup saya mendapatkan postMessage yang bekerja dengan jendela popup lintas domain menggunakan versi terbaru IE (11) dan API MessageChannel. Dan sejujurnya saya tidak dapat menemukan tempat lain di InterWebs selain jawaban ini yang menunjukkan bahwa skenario khusus ini harus berhasil. Adakah yang bisa menunjukkan contoh yang membuktikan bahwa itu berhasil? Saya akan berterima kasih selamanya.
Todd Menier
4
MessageChannel seharusnya tidak berfungsi karena alasan yang sama dengan postMessage. Microsoft perlu memperbaiki marshalling lintas proses. blogs.msdn.com/b/ieinternals/archive/2009/09/15/...
EricLaw
9
Jawaban ini menjengkelkan karena memberi kita harapan palsu. Jawabannya adalah: ini tidak akan berfungsi tanpa proxy karena postMessage diperlukan agar MessageChannel berfungsi (setidaknya di setiap demo yang pernah saya lihat). Kecuali jika seseorang menunjukkan kepada saya demo MessageChannel yang berfungsi tanpa postMessage atau postMessage ('name', '<domain>', [messageChannel.port2]) yang berfungsi lintas domain (Saya tidak bisa membuatnya berfungsi), saya tidak akan percaya ini bekerja tanpa bingkai proxy.
Akrikos
30

Buat halaman proxy di host yang sama dengan peluncur. Halaman proxy memiliki iframesumber dengan yang disetel ke halaman jarak jauh. PostMessage lintas asal sekarang akan berfungsi di IE10 seperti:

  • Halaman jarak jauh digunakan window.parent.postMessageuntuk melewatkan data ke halaman proxy. Karena ini menggunakan iframe, ini didukung oleh IE10
  • Halaman proxy digunakan window.opener.postMessageuntuk meneruskan data kembali ke halaman peluncur. Karena ini berada di domain yang sama - tidak ada masalah lintas sumber. Itu juga bisa langsung memanggil metode global di halaman peluncur jika Anda tidak ingin menggunakan postMessage - mis.window.opener.someMethod(data)

Contoh (semua URL fiktif)

Halaman peluncur di 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>

Halaman proxy di 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>

Halaman jarak jauh di 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>
LyphTEC
sumber
Jawaban Anda akan lebih baik jika menyertakan link ke halaman contoh Microsoft & halaman solusi yang ditautkan ke jawaban lain. Solusi: blogs.msdn.com/b/ieinternals/archive/2009/09/16/… Contoh (dari halaman solusi): debugtheweb.com/test/xdm/origin
Akrikos
Selain itu, halaman contoh Anda sekarang tertaut ke halaman GoDaddy tidak ditemukan.
Akrikos
8
Hah? ... semua URL adalah CONTOH dan tidak dimaksudkan untuk benar-benar mengarah ke halaman yang ada ... dari sumber yang terdaftar Anda dapat menentukan apa yang perlu dilakukan untuk membuatnya bekerja ..
LyphTEC
Terimakasih atas klarifikasinya. :-)
Akrikos
29

== SOLUSI KERJA DI 2020 tanpa iframe ==

Membangun jawaban dengan kusut, saya berhasil di IE11 [dan meniru mode IE10] menggunakan cuplikan berikut:

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

Kemudian saya dapat berkomunikasi menggunakan tumpukan postMessage yang khas, saya menggunakan satu utusan statis global dalam skenario saya (meskipun saya tidak menganggap itu penting, saya juga melampirkan kelas messenger saya)

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

Tidak peduli seberapa keras saya mencoba, saya tidak dapat membuat semuanya berfungsi di IE9 dan IE8

Konfigurasi saya di mana ini berfungsi:
Versi IE: 11.0.10240.16590, Perbarui versi: 11.0.25 (KB3100773)

Bruno Laurinec
sumber
6
Saya hanya harus mengatakan - jika ada orang lain yang melihat solusi ini berpikir "tidak mungkin, itu tidak mungkin memperbaikinya" - ya, itu sebenarnya memperbaiki ketidakmampuan untuk postMessage ke window.opener di IE11. Luar biasa.
dkr88
1
Tidak mungkin ... Saya seperti 2 hari mencoba dan ini "memecahkan" masalah
lmiguelmh
bekerja seperti pesona dan misterius !! (IE10.0.9200, win7)
Simon
Dapatkah Anda memberikan Contoh lengkap untuk solusi ini?
msm2020
1
@SidJonnala tidak juga, tapi saya akan merekomendasikan itu. Jika Anda segera menetapkan ulang ke halaman jarak jauh yang sebenarnya dan halaman Anda memerlukan waktu 3-4 detik untuk memuat [mungkin terjadi dari waktu ke waktu] maka Anda berisiko memuat halaman window.open ('/') dan membingungkan pengguna
Bruno Laurinec
2

Dibangun berdasarkan jawaban oleh LyphTEC dan Akrikos, solusi lain adalah membuat <iframe>dalam jendela sembulan kosong, yang menghindari kebutuhan untuk halaman proxy terpisah, karena sembulan kosong memiliki asal yang sama dengan pembukanya.

Halaman peluncur di 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>

Halaman jarak jauh di 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>

Saya tidak yakin seberapa rapuh ini, tetapi berfungsi di IE 11 dan Firefox 40.0.3.

menjerat
sumber
1
... dan sekarang tidak berfungsi (kegagalan diam di jendela popup ke <iframe>arah) di IE 11 ( 11.0.9600.18036, perbarui versi 11.0.23 (KB3087038)). Mungkin pembaruan keamanan terkini ( KB3087038 ) terlibat.
kusut
1

Saat ini, (2014-09-02), Taruhan terbaik Anda adalah menggunakan bingkai proxy seperti yang tercantum di entri blog msdn yang merinci solusi untuk masalah ini: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-implementation-issues-in-ie8-and-later /

Inilah contoh yang berfungsi: http://www.debugtheweb.com/test/xdm/origin/

Anda perlu menyiapkan bingkai proxy di halaman Anda yang memiliki asal yang sama dengan popup. Kirim informasi dari popup ke bingkai proxy menggunakan window.opener.frames[0]. Kemudian gunakan postMessage dari bingkai proxy ke halaman utama.

Akrikos
sumber
1

Solusi ini melibatkan penambahan situs ke Situs Terpercaya Internet Explore dan bukan di situs Intranet Lokal. Saya menguji solusi ini di Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 dan Windows 7 SP1 / IE 10.0.9200.17148. Halaman tidak boleh dimasukkan ke dalam Zona Intranet .

Jadi buka konfigurasi Internet Explorer (Tools> Internet Options> Security> Trusted Sites> Sites), dan tambahkan halaman, di sini saya menggunakan * untuk mencocokkan semua subdomain. Pastikan halaman tidak terdaftar di situs intranet lokal (Alat> Opsi Internet> Keamanan> Intranet Lokal> Situs> Lanjutan). Mulai ulang browser Anda dan uji lagi.

Tambahkan ke situs terpercaya di Internet Explorer

Di Windows 10 / Microsoft Edge Anda akan menemukan konfigurasi ini di Control Panel> Internet Options.

MEMPERBARUI

Jika ini tidak berhasil, Anda dapat mencoba mengatur ulang semua pengaturan Anda di Alat> Opsi Internet> Pengaturan Lanjutan> Atur ulang pengaturan Internet Explorer dan kemudian Atur Ulang: gunakan dengan hati - hati ! Kemudian Anda perlu me-reboot sistem Anda. Setelah itu tambahkan situs tersebut ke situs Terpercaya.

Lihat di zona apa halaman Anda berada di File> Properties atau gunakan klik kanan.

Properti halaman di internet explorer

MEMPERBARUI

Saya menggunakan intranet perusahaan dan terkadang berfungsi dan terkadang tidak (konfigurasi otomatis? Saya bahkan mulai menyalahkan proxy perusahaan). Pada akhirnya saya menggunakan solusi ini https://stackoverflow.com/a/36630058/2692914 .

lmiguelmh
sumber
0

Q ini sudah lama tetapi untuk itulah easyXDM, mungkin memeriksanya sebagai kemungkinan fallback ketika Anda mendeteksi browser yang tidak mendukung html5 .postMessage:

https://easyxdm.net/

Ini menggunakan pembungkus VBObject dan semua jenis hal yang tidak ingin Anda tangani untuk mengirim pesan lintas domain antara jendela atau bingkai di mana window.postMessage gagal untuk berbagai versi IE (dan mungkin edge, masih tidak yakin 100% pada dukungan Edge memiliki tetapi tampaknya juga membutuhkan solusi untuk .postMessage)

OG Sean
sumber
-3

MessageChannel tidak berfungsi untuk IE 9-11 di antara jendela / tab karena bergantung pada postMessage, yang masih rusak dalam skenario ini. Solusi "terbaik" adalah memanggil fungsi melalui window.opener (mis. Window.opener.somefunction ("somedata")).

Solusi lebih detail di sini

pengguna1337489
sumber
1
Itu tidak berfungsi dalam pengaturan lintas sumber, yang merupakan salah satu prasyarat dalam pertanyaan.
PhistucK