在 IE10中跨源邮件是否中断?

我试图使一个微不足道的 postMessage例子工作..。

  • 在 IE10
  • 在 windows/tab 之间(相对于 iframe)
  • 跨越起源

去掉以下任何一个条件,事情就会顺利进行: -)

但据我所知,只有当两个窗口共享一个原点时,窗口间 postMessage才能在 IE10中工作。(实际上——奇怪的是——这种行为比那个稍微宽容一些: 共享 主持人的两个不同的起源似乎也起作用了)。

这是一个有文档记录的 bug 吗? 有什么变通方法或其他建议吗?

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


更多细节 + 例子..。

启动页 小样

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

启动页 小样

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

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

73079 次浏览

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:


Worth noting: the link in that answer you linked to states that postMessage isn'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.

As for postMessage itself, http://caniuse.com/#feat=x-doc-messaging notably 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:

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.

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

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

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") ).

Workaround in more detail here

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

  • Remote page uses window.parent.postMessage to pass data to proxy page. As this uses iframes, it's supported by IE10
  • Proxy page uses window.opener.postMessage to 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)

Sample (all URLs are fictitous)

Launcher page at 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

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

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

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/

Here's the working example: 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.

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.

Launcher page at 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

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

== WORKING SOLUTION IN 2020 without iframe ==

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

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

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

    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

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

This solution involves adding the site to Internet Explore's Trusted Sites and not in 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.

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't listed in the Local intranet sites (Tools > Internet Options > Security > Local Intranet > Sites > Advanced). Restart your browser and test again.

Add to trusted sites in Internet Explorer

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

UPDATE

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

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

Page properties in 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.

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 :

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)