PostMessage có nguồn gốc chéo có bị hỏng trong IE10 không?


91

Tôi đang cố gắng làm cho một postMessageví dụ tầm thường hoạt động ...

  • trong IE10
  • giữa các cửa sổ / tab (so với iframe)
  • qua các nguồn gốc

Loại bỏ bất kỳ một trong những điều kiện này và mọi thứ hoạt động tốt :-)

Nhưng theo như tôi có thể nói, giữa cửa sổ postMessagedường như chỉ hoạt động trong IE10 khi cả hai cửa sổ chia sẻ một nguồn gốc. (Chà, trên thực tế - và kỳ lạ thay - hành vi này hơi dễ dãi hơn thế: hai nguồn gốc khác nhau có chung một vật chủ dường như cũng hoạt động).

Đây có phải là một lỗi đã được ghi nhận không? Bất kỳ giải pháp thay thế hoặc lời khuyên khác?

(Lưu ý: Câu hỏi này liên quan đến các vấn đề, nhưng câu trả lời của nó là về IE8 và IE9 - không phải 10)


Thêm chi tiết + ví dụ ...

demo trang launcher

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

giới thiệu trang giới thiệu

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

Điều này hoạt động tại: http://jsbin.com/ahuzir/1 - vì cả hai trang đều được lưu trữ tại cùng một nguồn gốc (jsbin.com). Nhưng di chuyển trang thứ hai đến bất kỳ nơi nào khác và nó không thành công trong IE10.



5
Vui lòng xem xét việc thay đổi câu trả lời được chấp nhận thành câu trả lời cho câu hỏi thay vì liệt kê MessageChannel là lựa chọn tốt nhất của bạn khi MessageChannel yêu cầu postMessage để nó hoạt động. Tôi đã dành hơn một giờ chơi với MessageChannel chỉ để thấy rằng giải pháp khả thi duy nhất là proxy iframe.
Akrikos

1
Nếu window.open của bạn chỉ là một hộp thoại bật lên, bạn có thể tránh nó hoàn toàn và sử dụng iframe theo phương thức js. Một cái gì đó như jQuery Dialog hoặc Bootstrap Modal là cách tôi triển khai nó. Sau đó, bạn có thể sử dụng window.parent.postMessagetrong IE.
súng trường vào

@Bosh như câu trả lời của tôi dường như làm việc vào năm 2018 và không yêu cầu khung proxy, bạn sẽ nhớ thiết lập thatone là câu trả lời được chấp nhận vì nó dường như giúp đỡ cho chúng tôi, những người không may người vẫn phải hỗ trợ tức cũ
Bruno Laurinec

Câu trả lời:


62

Tôi đã nhầm khi ban đầu đăng câu trả lời này: nó không thực sự hoạt động trong IE10. Rõ ràng mọi người đã thấy điều này hữu ích vì những lý do khác nên tôi sẽ để lại nó cho hậu thế. Câu trả lời gốc bên dưới:


Đáng chú ý: liên kết trong câu trả lời mà bạn đã liên kết đến các trạng thái postMessagekhông có nguồn gốc chéo cho các cửa sổ riêng biệt trong IE8 và IE9 - tuy nhiên, nó cũng được viết vào năm 2009, trước khi IE10 xuất hiện. Vì vậy, tôi sẽ không coi đó là dấu hiệu cho thấy nó đã được sửa trong IE10.

Đối với postMessagechính nó, http://caniuse.com/#feat=x-doc-messaging đáng chú ý chỉ ra rằng nó vẫn bị hỏng trong IE10, có vẻ như khớp với bản demo của bạn. Trang caniuse liên kết đến bài viết này , trong đó có một trích dẫn rất có liên quan:

Internet Explorer 8+ hỗ trợ một phần tính năng nhắn tin trên nhiều tài liệu: nó hiện hoạt động với iframe, nhưng không hoạt động với các cửa sổ mới. Tuy nhiên, Internet Explorer 10 sẽ hỗ trợ MessageChannel. Firefox hiện hỗ trợ nhắn tin nhiều tài liệu, nhưng không hỗ trợ MessageChannel.

Vì vậy, đặt cược tốt nhất của bạn có lẽ là có một đường mã hóa MessageChanneldựa trên và dự phòng postMessagenếu điều đó không tồn tại. Nó sẽ không giúp bạn hỗ trợ IE8 / IE9, nhưng ít nhất nó sẽ hoạt động với IE10.

Tài liệu trên MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx


8
Làm thế nào bạn sẽ tạo một MessageChannelcodepath dựa trên hoạt động? Bạn vẫn cần hoạt động postMessageđể chuyển cổng của kênh sang cửa sổ khác.
balpha

1
Sử dụng postMessagevới MessageChannelAPI mới sẽ hoạt động trên các cửa sổ và nguồn gốc mới. Tôi đoán là công việc này hơi khó xử, nhưng về cơ bản: postMessage('foo', '*')là xấu, postMessage('foo', [messageChannel.port2])là tốt.
ShZ

3
Tôi không thể cho postMessage hoạt động với cửa sổ bật lên tên miền chéo bằng cách sử dụng phiên bản mới nhất của IE (11) và API MessageChannel. Và thành thật mà nói, tôi không thể tìm thấy bất kỳ nơi nào khác trên InterWebs ngoài câu trả lời này chỉ ra rằng kịch bản cụ thể này sẽ hoạt động. Bất cứ ai có thể chỉ vào một ví dụ chứng minh rằng nó hoạt động? Tôi sẽ mãi mãi biết ơn.
Todd Menier

4
MessageChannel sẽ không hoạt động vì lý do tương tự như postMessage. Microsoft cần khắc phục sự cố kết hợp nhiều quy trình. blogs.msdn.com/b/ieinternals/archive/2009/09/15/...
EricLaw

9
Câu trả lời này thật khó chịu vì nó cho chúng ta hy vọng sai lầm. Câu trả lời là: nó sẽ không hoạt động nếu không có proxy vì cần có postMessage để MessageChannel hoạt động (ít nhất là trong mọi bản demo mà tôi đã xem). Trừ khi ai đó cho tôi xem bản demo MessageChannel hoạt động mà không có postMessage hoặc postMessage ('name', '<domain>', [messageChannel.port2]) đang hoạt động trên nhiều miền (tôi không thể làm cho nó hoạt động), tôi sẽ không tin điều này hoạt động mà không có khung proxy.
Akrikos

30

Tạo trang proxy trên cùng một máy chủ làm trình khởi chạy. Trang proxy có một iframenguồn được đặt thành trang từ xa. PostMessage có nguồn gốc chéo giờ sẽ hoạt động trong IE10 như sau:

  • Sử dụng trang từ xa window.parent.postMessage để chuyển dữ liệu đến trang proxy. Vì điều này sử dụng iframe, nó được hỗ trợ bởi IE10
  • Trang proxy sử dụng window.opener.postMessageđể chuyển dữ liệu trở lại trang trình khởi chạy. Vì đây là trên cùng một miền - không có vấn đề về nguồn gốc chéo. Nó cũng có thể gọi trực tiếp các phương thức toàn cục trên trang launcher nếu bạn không muốn sử dụng postMessage - ví dụ:window.opener.someMethod(data)

Mẫu (tất cả các URL là hư cấu)

Trang khởi chạy tại 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>

Trang proxy tại 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>

Trang từ xa tại 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>

Câu trả lời của bạn sẽ tốt hơn nếu nó bao gồm một liên kết đến trang ví dụ và trang giải pháp của Microsoft được liên kết đến trong các câu trả lời khác. Cách giải quyết: blogs.msdn.com/b/ieinternals/archive/2009/09/16/... Ví dụ (từ trang workaround): debugtheweb.com/test/xdm/origin
Akrikos

Ngoài ra, trang mẫu của bạn hiện không tìm thấy liên kết đến một trang tin thần.
Akrikos

8
Huh? ... tất cả các URL là những ví dụ và không có nghĩa là để thực sự điểm đến trang hiện ... từ nguồn được liệt kê, bạn có thể xác định những gì cần phải được thực hiện để làm cho nó làm việc ..
LyphTEC

Cảm ơn bạn đã làm rõ. :-)
Akrikos

29

== GIẢI PHÁP LÀM VIỆC NĂM 2020 mà không cần iframe ==

Dựa trên câu trả lời theo mớ, tôi đã thành công trong IE11 [và chế độ giả lập IE10] bằng cách sử dụng đoạn mã sau:

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

Sau đó, tôi đã có thể giao tiếp bằng cách sử dụng ngăn xếp postMessage điển hình, tôi đang sử dụng một trình nhắn tin tĩnh toàn cầu trong kịch bản của mình (dù sao tôi không cho rằng nó có ý nghĩa gì cả, tôi cũng đang đính kèm lớp sứ giả của mình)

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

Dù cố gắng đến đâu, tôi vẫn không thể làm cho mọi thứ hoạt động trên IE9 và IE8

Cấu hình của tôi nơi nó đang hoạt động:
Phiên bản IE: 11.0.10240.16590, Phiên bản cập nhật: 11.0.25 (KB3100773)


6
Tôi chỉ phải nói - trong trường hợp bất kỳ ai khác đang xem cách giải quyết này và nghĩ rằng "không có cách nào, điều đó không thể khắc phục được nó" - vâng, nó thực sự đã sửa lỗi không thể postMessage vào window.opener trong IE11. Không thể tin được.
dkr88

1
Không có cách nào ... Tôi giống như 2 ngày cố gắng và điều này "giải quyết" vấn đề
lmiguelmh

hoạt động như sự quyến rũ và bí ẩn !! (IE10.0.9200, win7)
Simon

Bạn có thể cung cấp một ví dụ đầy đủ cho cách giải quyết này không?
msm2020

1
@SidJonnala không thực sự, nhưng tôi muốn giới thiệu điều đó. Nếu bạn gán lại cho trang từ xa thực tế ngay lập tức và trang của bạn mất 3-4 giây để tải [có thể thỉnh thoảng xảy ra] thì bạn có nguy cơ trang window.open ('/') của mình tải và gây nhầm lẫn cho người dùng
Bruno Laurinec

2

Dựa trên câu trả lời của LyphTEC và Akrikos, một công việc khác là tạo một <iframe>cửa sổ bật lên trống trong một cửa sổ bật lên trống, điều này tránh cần một trang proxy riêng biệt, vì cửa sổ bật lên trống có cùng nguồn gốc với trình mở của nó.

Trang khởi chạy tại 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>

Trang từ xa tại 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>

Tôi không chắc điều này mong manh đến mức nào, nhưng nó đang hoạt động trên IE 11 và Firefox 40.0.3.


1
... và bây giờ nó không hoạt động (lỗi im lặng trong cửa sổ bật lên <iframe>hướng) trong IE 11 ( 11.0.9600.18036, các phiên bản cập nhật 11.0.23 (KB3087038)). Có thể có liên quan đến bản cập nhật bảo mật gần đây ( KB3087038 ).
rối

1

Ngay bây giờ, (2014-09-02), Tốt nhất là bạn nên sử dụng khung proxy như được lưu ý trong bài đăng trên blog msdn hướng dẫn chi tiết cách giải quyết cho vấn đề này: https://blogs.msdn.microsoft.com/ieinternals/2009 / 09/15 / html5-implement-problem-in-ie8-and-later /

Đây là ví dụ hoạt động: http://www.debugtheweb.com/test/xdm/origin/

Bạn cần thiết lập khung proxy trên trang của mình có cùng nguồn gốc với cửa sổ bật lên. Gửi thông tin từ cửa sổ bật lên đến khung proxy bằng cách sử dụng window.opener.frames[0]. Sau đó sử dụng postMessage từ khung proxy đến trang chính.


1

Giải pháp này liên quan đến việc thêm trang web vào các Trang web đáng tin cậy của Internet Explore chứ không phải trong các trang Mạng nội bộ cục bộ. Tôi đã thử nghiệm giải pháp này trong Windows 10 / IE 11.0.10240.16384, Windows 10 / Microsoft Edge 20.10240.16384.0 và Windows 7 SP1 / IE 10.0.9200.17148. Trang không được bao gồm trong Vùng mạng nội bộ .

Vì vậy, hãy mở cấu hình Internet Explorer (Công cụ> Tùy chọn Internet> Bảo mật> Trang web đáng tin cậy> Trang web), và thêm trang, ở đây tôi sử dụng * để khớp với tất cả các miền phụ. Đảm bảo rằng trang không được liệt kê trong các trang mạng nội bộ Cục bộ (Công cụ> Tùy chọn Internet> Bảo mật> Mạng nội bộ cục bộ> Trang web> Nâng cao). Khởi động lại trình duyệt của bạn và kiểm tra lại.

Thêm vào các trang web đáng tin cậy trong Internet Explorer

Trong Windows 10 / Microsoft Edge bạn sẽ tìm thấy cấu hình này trong Control Panel> Internet Options.

CẬP NHẬT

Nếu cách này không hiệu quả, bạn có thể thử đặt lại tất cả cài đặt của mình trong Công cụ> Tùy chọn Internet> Cài đặt nâng cao> Đặt lại cài đặt Internet Explorer và sau đó Đặt lại: hãy sử dụng cẩn thận ! Sau đó, bạn sẽ cần phải khởi động lại hệ thống của mình. Sau đó, thêm các trang web vào các trang web Tin cậy.

Xem trang của bạn nằm trong vùng nào trong Tệp> Thuộc tính hoặc sử dụng nhấp chuột phải.

Thuộc tính trang trong trình khám phá internet

CẬP NHẬT

Tôi đang ở trong một mạng nội bộ của công ty và đôi khi nó hoạt động và đôi khi nó không hoạt động (cấu hình tự động? Tôi thậm chí bắt đầu đổ lỗi cho proxy của công ty). Cuối cùng thì tôi đã sử dụng giải pháp này https://stackoverflow.com/a/36630058/2692914 .


0

Q này đã cũ nhưng đây là những gì easyXDM dành cho, có thể kiểm tra xem nó như một dự phòng tiềm năng khi bạn phát hiện một trình duyệt không hỗ trợ html5 .postMessage:

https://easyxdm.net/

Nó sử dụng trình bao bọc VBObject và tất cả các loại nội dung mà bạn không bao giờ muốn phải xử lý để gửi thông báo tên miền chéo giữa các cửa sổ hoặc khung mà window.postMessage không thành công đối với các phiên bản IE khác nhau (và có thể, vẫn không chắc chắn 100% được hỗ trợ Edge có nhưng dường như nó cũng cần một giải pháp thay thế cho .postMessage)


-3

MessageChannel không hoạt động cho IE 9-11 giữa các cửa sổ / tab vì nó dựa trên postMessage, vẫn bị hỏng trong trường hợp này. Cách giải quyết "tốt nhất" là gọi một hàm thông qua window.opener (tức là. Window.opener.some Chức năng ("somedata")).

Cách giải quyết chi tiết hơn tại đây


1
Điều đó không hoạt động trong cài đặt nguồn gốc chéo, đây là một trong những điều kiện tiên quyết trong câu hỏi.
PhistucK
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.