IE10中的跨源postMessage是否被破坏?

时间:2013-04-26 00:32:32

标签: html5 cross-browser compatibility internet-explorer-10 postmessage

我正在努力制作一个简单的postMessage示例工作......

  • 在IE10中
  • 在windows / tabs(与iframes)之间
  • 跨越起源

删除这些条件中的任何一个,并且工作正常: - )

但据我所知,当两个窗口共享一个原点时,窗口postMessage之间只能在IE10中工作。 (嗯,事实上 - 奇怪的是 - 行为稍微宽松一点:共享主机的两个不同的起源似乎也有效。)

这是一个记录在案的错误吗?任何变通办法或其他建议?

(注:This question触及问题,但its answer是关于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中失败了。

8 个答案:

答案 0 :(得分:59)

当我最初发布这个答案时我错了:它实际上并不适用于IE10。显然人们已经发现这有用了其他原因因此我将其留给后代。原答案如下:


值得注意的是:在答案中你链接到postMessage不是IE8和IE9中单独窗口的交叉来源的答案中的链接 - 然而,它也是在2009年写的,在IE10出现之前。因此,我不会将其视为在IE10中修复的指示。

对于postMessage本身,http://caniuse.com/#feat=x-doc-messaging显然表明它在IE10中仍然存在,这似乎与您的演示相匹配。 caniuse页面链接到this article,其中包含非常相关的引用:

  

Internet Explorer 8+部分支持跨文档消息传递:它   目前适用于iframe,但不适用于新窗口。 IE浏览器   但是,10将支持MessageChannel。 Firefox目前支持   跨文档消息传递,但不是MessageChannel。

所以你最好的选择可能是基于MessageChannel的代码路径,如果不存在则回退到postMessage。它不会得到IE8 / IE9支持,但至少它可以与IE10一起使用。

MessageChannel上的文档:http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx

答案 1 :(得分:29)

在与启动器相同的主机上创建代理页面。代理页面的iframe源设置为远程页面。跨域postMessage现在可以在IE10中工作:

  • 远程页面使用window.parent.postMessage将数据传递到代理页面。由于这使用iframe,因此IE10支持
  • 代理页面使用window.opener.postMessage将数据传递回启动器页面。由于这是在同一个域 - 没有跨源问题。如果您不想使用postMessage,它也可以直接在启动器页面上调用全局方法 - 例如。 window.opener.someMethod(data)

示例(所有网址都是虚构的)

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>

答案 2 :(得分:22)

在纠结的答案基础上,我使用以下片段在IE11 [并模拟IE10模式]取得了成功:

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

然后我能够使用典型的postMessage堆栈进行通信,我在我的场景中使用了一个全局静态信使(尽管我并不认为它有任何重要性,我&#39; m还附上我的信使班)

{{1}}

无论我怎么努力,我都无法在IE9和IE8上运行

我的配置在哪里工作:
IE版本:11.0.10240.16590,更新版本:11.0.25(KB3100773)

答案 3 :(得分:2)

在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中有效。

答案 4 :(得分:1)

目前,(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 :(得分:0)

此解决方案涉及将站点添加到Internet Explore的受信任站点,并将不是添加到本地Intranet站点中。我在Windows 10 / IE 11.0.10240.16384,Windows 10 / Microsoft Edge 20.10240.16384.0和Windows 7 SP1 / IE 10.0.9200.17148中测试了此解决方案。 该网页不得包含在Intranet区域

打开Internet Explorer配置(工具&gt; Internet选项&gt;安全&gt;可信站点&gt;站点),然后添加页面,此处我使用*来匹配所有子域。 确保本地Intranet网站中列出 页面(工具&gt; Internet选项&gt;安全&gt;本地Intranet&gt;网站&gt;高级)。重新启动您的网站浏览器并再次测试。

Add to trusted sites in Internet Explorer

Windows 10 / Microsoft Edge 中,您将在控制面板&gt;中找到此配置。互联网选项。

<强>更新

如果这不起作用,您可以尝试在工具&gt;中重置所有设置。互联网选项&gt;高级设置&gt;重置Internet Explorer设置然后重置:使用警告 !然后,您将需要重新启动系统。之后,将站点添加到可信站点。

在File&gt;中查看您的网页所在的区域属性或使用右键单击。

Page properties in internet explorer

<强>更新

我在企业内部网,有时它可以工作,有时它不工作(自动配置?我甚至开始责怪公司代理)。最后我使用了这个解决方案https://stackoverflow.com/a/36630058/2692914

答案 6 :(得分:0)

此Q很旧,但这就是easyXDM的用途,当您检测到不支持html5 .postMessage的浏览器时,可以将其检出为潜在的回退:

https://easyxdm.net/

它使用VBObject包装器和您永远不需要处理的所有类型的东西来在窗口或框架之间发送跨域消息,其中window.postMessage对于各种IE版本均失败(并且边缘可能仍然不确定100%在Edge的支持上,但似乎也需要针对.postMessage的变通方法)

答案 7 :(得分:-3)

MessageChannel在Windows / tabs之间不适用于IE 9-11,因为它依赖于postMessage,在这种情况下仍然会破坏。最好的&#34;解决方法是通过window.opener调用一个函数(即window.opener.somefunction(&#34; somedata&#34;))。

Workaround in more detail here