I'm trying to make a trivial postMessage
example work...
- in IE10
- between windows/tabs (vs. iframes)
- across origins
Remove any one of these conditions, and things work fine :-)
But as far as I can tell, between-window postMessage
only 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 host seem to work, too).
Is this a documented bug? Any workarounds or other advice?
(Note: This question touches on the issues, but its answer is about IE8 and IE9 -- not 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.
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
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>
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 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)
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)
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.
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.
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.
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.
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.
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") ).
来源:https://stackoverflow.com/questions/16226924/is-cross-origin-postmessage-broken-in-ie10