Html 跨域 postMessage 在 IE10 中被破坏了吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16226924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 07:52:51  来源:igfitidea点击:

Is cross-origin postMessage broken in IE10?

htmlcross-browsercompatibilityinternet-explorer-10postmessage

提问by Bosh

I'm trying to make a trivial postMessageexample work...

我正在尝试制作一个简单的postMessage示例...

  • in IE10
  • between windows/tabs (vs. iframes)
  • across origins
  • 在 IE10
  • 在窗口/选项卡之间(与 iframe)
  • 跨越起源

Remove any one of these conditions, and things work fine :-)

删除这些条件中的任何一个,一切正常:-)

But as far as I can tell, between-window postMessageonly appears to work in IE10 when both windows share an origin. (Well, in fact -- and weirdly -- the behavior is slightly more permissive than that: two different origins that share a hostseem to work, too).

但据我所知,postMessage当两个窗口共享一个原点时,窗口间似乎只在 IE10 中工作。(嗯,事实上——而且奇怪的是——这种行为比那更宽容:共享一个主机的两个不同的起源似乎也有效)。

Is this a documented bug? Any workarounds or other advice?

这是一个记录在案的错误吗?任何解决方法或其他建议?

(Note: This questiontouches on the issues, but its answeris about IE8 and IE9 -- not 10)

(注意:这个问题涉及问题,但它的答案是关于 IE8 和 IE9——而不是 10)



More details + example...

更多细节+示例...

launcher page 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>

launched page demo

启动页面演示

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

This works at: http://jsbin.com/ahuzir/1-- because both pages are hosted at the same origin (jsbin.com). But move the second page anywhere else, and it fails in IE10.

这适用于:http: //jsbin.com/ahuzir/1——因为两个页面都托管在同一来源 (jsbin.com)。但是将第二页移动到其他任何地方,它在 IE10 中失败。

采纳答案by ShZ

I was mistaken when I originally posted this answer: it doesn't actually work in IE10.Apparently people have found this useful for other reasons so I'm leaving it up for posterity. Original answer below:

当我最初发布这个答案时我错了:它实际上在 IE10 中不起作用。显然人们出于其他原因发现这很有用,所以我将其留给后代。原答案如下:



Worth noting: the link in that answer you linked to states that postMessageisn't cross origin for separate windows in IE8 and IE9 -- however, it was also written in 2009, before IE10 came around. So I wouldn't take that as an indication that it's fixed in IE10.

值得注意的是:该答案中的链接指向的状态postMessage不是 IE8 和 IE9 中单独窗口的跨源状态——但是,它也是在 2009 年编写的,在 IE10 出现之前。所以我不会认为它已在 IE10 中修复。

As for postMessageitself, http://caniuse.com/#feat=x-doc-messagingnotably indicates that it's still broken in IE10, which seems to match up with your demo. The caniuse page links to this article, which contains a very relevant quote:

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

Internet Explorer 8+ partially supports cross-document messaging: it currently works with iframes, but not new windows. Internet Explorer 10, however, will support MessageChannel. Firefox currently supports cross-document messaging, but not MessageChannel.

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

So your best bet is probably to have a MessageChannelbased codepath, and fallback to postMessageif that doesn't exist. It won't get you IE8/IE9 support, but at least it'll work with IE10.

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

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

文档MessageChannelhttp: //msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx

回答by LyphTEC

Create a proxy page on the same host as launcher. Proxy page has an iframewith source set to remote page. Cross-origin postMessage will now work in IE10 like so:

在与启动器相同的主机上创建代理页面。代理页面的iframe源设置为远程页面。跨源 postMessage 现在将在 IE10 中工作,如下所示:

  • Remote page uses window.parent.postMessageto pass data to proxy page. As this uses iframes, it's supported by IE10
  • Proxy page uses window.opener.postMessageto pass data back to launcher page. As this is on same domain - there are no cross-origin issues. It can also directly call global methods on the launcher page if you don't want to use postMessage - eg. window.opener.someMethod(data)
  • 远程页面用于window.parent.postMessage将数据传递给代理页面。由于它使用 iframe,因此 IE10 支持
  • 代理页面用于window.opener.postMessage将数据传回启动器页面。由于这是在同一个域上 - 没有跨域问题。如果您不想使用 postMessage,它也可以直接调用启动器页面上的全局方法 - 例如。window.opener.someMethod(data)


Sample (all URLs are fictitous)

示例(所有网址均为虚构)

Launcher page at http://example.com/launcher.htm

启动器页面位于 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>

Proxy page at http://example.com/proxy.htm

代理页面位于 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>

Remote page at http://example.net/remote.htm

远程页面位于 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>

回答by Bruno Laurinec

== WORKING SOLUTION IN 2020 without iframe ==

== 2020 年没有 iframe 的工作解决方案 ==

Building on answer by tangle, I had success in IE11 [and emulated IE10 mode] using following snippet:

基于缠结的答案,我使用以下代码段在 IE11 [和模拟 IE10 模式] 中取得了成功:

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

Then I was able to communicate using typical postMessage stack, I'm using one global static messenger in my scenario (alotough I don't suppose it's of any signifficance, I'm also attaching my messenger class)

然后我能够使用典型的 postMessage 堆栈进行通信,我在我的场景中使用了一个全局静态信使(虽然我认为它没有任何意义,我还附上了我的信使类)

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

No matter how hard I tried, I wasn't able to make things work on IE9 and IE8

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

My config where it's working:
IE version: 11.0.10240.16590, Update versions: 11.0.25 (KB3100773)

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

回答by tangle

Building upon the answers by LyphTEC and Akrikos, another work-around is to create an <iframe>within a blank popup window, which avoids the need for a separate proxy page, since the blank popup has the same origin as its opener.

基于 LyphTEC 和 Akrikos 的答案,另一种解决方法是<iframe>在空白弹出窗口中创建一个,这样就不需要单独的代理页面,因为空白弹出窗口与其开启者具有相同的来源。

Launcher page at http://example.com/launcher.htm

启动器页面位于 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>

Remote page at http://example.net/remote.htm

远程页面位于 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>

I'm not sure how fragile this is, but it is working in IE 11 and Firefox 40.0.3.

我不确定这有多脆弱,但它在 IE 11 和 Firefox 40.0.3 中工作。

回答by lmiguelmh

This solution involves adding the site to Internet Explore's Trusted Sites and notin the Local Intranet sites. I tested this solution in Windows 10/IE 11.0.10240.16384, Windows 10/Microsoft Edge 20.10240.16384.0 and Windows 7 SP1/IE 10.0.9200.17148. The page must not be included in the Intranet Zone.

此解决方案涉及将站点添加到 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 区域中

So open Internet Explorer configuration (Tools > Internet Options > Security > Trusted Sites > Sites), and add the page, here I use * to match all the subdomains. Make sure the page isn'tlisted in the Local intranet sites (Tools > Internet Options > Security > Local Intranet > Sites > Advanced).Restart your browser and test again.

所以打开Internet Explorer 配置(工具> Internet 选项> 安全> 可信站点> 站点),并添加页面,这里我使用* 来匹配所有子域。确保页面在本地 Intranet 站点中列出(工具 > Internet 选项 > 安全 > 本地 Intranet > 站点 > 高级)。重新启动浏览器并再次测试。

Add to trusted sites in Internet Explorer

添加到 Internet Explorer 中的受信任站点

In Windows 10/Microsoft Edgeyou will find this configuration in Control Panel > Internet Options.

Windows 10/Microsoft Edge 中,您将在控制面板 > Internet 选项中找到此配置。

UPDATE

更新

If this doesn't work you could try resetting all your settings in Tools > Internet Options > Advanced Settings > Reset Internet Explorer settingsand then Reset: use it with caution! Then you will need to reboot your system. After that add the sites to the Trusted sites.

如果这不起作用,你可以尝试重置所有的设置工具> Internet选项>高级设置>重置Internet Explorer设置,然后复位:有使用它小心!然后,您将需要重新启动系统。之后,将站点添加到受信任站点。

See in what zone your page is in File > Properties or using right click.

在“文件”>“属性”中或使用右键单击查看您的页面位于哪个区域。

Page properties in internet explorer

Internet Explorer 中的页面属性

UPDATE

更新

I am in a corporate intranet and sometimes it works and sometimes it doesn't (automatic configuration? I even started to blame the corporate proxy). In the end I used this solution https://stackoverflow.com/a/36630058/2692914.

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

回答by Akrikos

Right now, (2014-09-02), Your best bet is to use a proxy frame as noted in the msdn blog post that details a workaround for this issue: https://blogs.msdn.microsoft.com/ieinternals/2009/09/15/html5-implementation-issues-in-ie8-and-later/

现在,(2014-09-02),您最好的选择是使用 msdn 博客文章中所述的代理框架,该文章详细介绍了此问题的解决方法:https: //blogs.msdn.microsoft.com/ieinternals/2009 /09/15/html5-implementation-issues-in-ie8-and-later/

Here's the working example: http://www.debugtheweb.com/test/xdm/origin/

这是工作示例:http: //www.debugtheweb.com/test/xdm/origin/

You need to set up a proxy frame on your page that has the same origin as the popup. Send information from the popup to the proxy frame using window.opener.frames[0]. Then use postMessage from the proxy frame to the main page.

您需要在您的页面上设置一个与弹出窗口具有相同来源的代理框架。使用 将信息从弹出窗口发送到代理框架window.opener.frames[0]。然后使用 postMessage 从代理框架到主页。

回答by OG Sean

This Q is old but this is what easyXDM is for, maybe check it out as a potential fallback when you detect a browser that does not support html5 .postMessage :

这个 Q 很旧,但这就是 easyXDM 的用途,当您检测到不支持 html5 .postMessage 的浏览器时,也许可以将其检查为潜在的后备:

https://easyxdm.net/

https://easyxdm.net/

It uses VBObject wrapper and all types of stuff you'd never want to have to deal with to send cross domain messages between windows or frames where window.postMessage fails for various IE versions (and edge maybe, still not sure 100% on the support Edge has but it seems to also need a workaround for .postMessage)

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

回答by user1337489

MessageChannel doesn't work for IE 9-11 between windows/tabs since it relies on postMessage, which is still broken in this scenario. The "best" workaround is to call a function through window.opener (ie. window.opener.somefunction("somedata") ).

MessageChannel 不适用于窗口/选项卡之间的 IE 9-11,因为它依赖于 postMessage,在这种情况下它仍然被破坏。“最佳”解决方法是通过 window.opener 调用函数(即 window.opener.somefunction("somedata") )。

Workaround in more detail here

更详细的解决方法在这里