PostMessage все еще не работает на IE11?
Кажется, что window.postMessage все еще не работает в IE 11, когда сообщение
- между окном и дочерним всплывающим окном / вкладкой с window.open
- когда он отправляется из разных доменов [или в некоторых случаях из одного домена, см. обновление 16/01]
Были похожие проблемы с IE 8/9/10, но эта функция была помечена как "поддерживаемая" в IE 11 из "частично поддерживаемой" в IE 10
Вот пример кода, который работает на chrome / ff, но не на IE:
$(document).ready(function() {
$('#log').append('listening...');
window.addEventListener("message", function(e){
$('#log').append("Received message: " + JSON.stringify(e.data));
}, false);
$('button').click(function() {
window.open('http://jsbin.com/eQeSeros/1', 'popup','menubar=no, status=no, scrollbars=no, menubar=no, width=200, height=100');
});
});
Дочернее всплывающее окно (jsbin): (не будет работать, если не открыто jsfiddle)
$(document).ready(function() {
$('body').append('sending...');
window.opener.postMessage("Hello?", "http://fiddle.jshell.net");
$('body').append('sent...');
});
Я прочитал из поста Является ли пост-сообщение кросс-происхождения сломанным в IE10? что мы можем использовать MessageChannel
вместо postMessage
, но, читая документ, я не нашел, как использовать его в моем реальном случае, потому что вы должны передать порт дочернему окну.
Перед отправкой сообщения существует цепочка перенаправления, поэтому, даже если я смогу отправить порт, я потеряю любой объект js, отправленный изначально / до перенаправления.
Есть идеи по замене?
Обновление 14/01: я думаю о передаче моих данных в заголовке окна / вкладки и регулярно проверяю этот заголовок у родителя... но это было бы довольно подвохом.
Обновление 16/01: действительно плохая часть заключается в том, что он действительно работает, даже если сообщение отправлено из того же домена, но после перенаправления другим доменом.
Вот пример: http://jsfiddle.net/L4YzG/13/ открывает всплывающее окно http://jsbin.com/eQeSeros/4/edit которое перенаправляет на http://jsfiddle.net/mxS8Q/2/ (что публикует сообщение)
Если вы измените всплывающее окно с URL-адресом непосредственно по окончательным перенаправлениям URL-адреса на http://jsfiddle.net/mxS8Q/2/show это будет работать в IE, поскольку между открытием и публикацией нет другого домена
Я все еще работаю над подвохом заголовка окна. мы не можем получить заголовок окна, когда он находится в другом домене, но если он возвращается в jsfiddle, заголовок доступен (предыдущей проблемы с postMessage не было). Вот пример: http://jsfiddle.net/L4YzG/14/... Это может быть альтернативное решение, но я только что увидел кое-что о передаче данных в cookie, его просто нужно протестировать.
Обновление 04/02: передача информации в заголовке недостаточна, если она работает хорошо, если конечные домены совпадают, но не в междоменном. Я хотел внедрить iframe того же домена, чтобы передать эту информацию, но я также не могу совместно использовать дочерний объект окна (postMessage нужен сериализуемый объект).
Наконец, я попытался поделиться cookie (созданным и полученным в js) между введенным iframe и дочерним окном, это хорошо работает на chrome & ff, но все еще не может получить его правильно с IE. После добавления заголовков P3P все заработало нормально, похоже, это и есть правильное решение. У Safari, похоже, есть некоторые проблемы с этой техникой, поэтому я просто оставляю эту технику резервной.
4 ответа
Это сломано? Ну вроде как.
Я попробовал разные идеи и не смог заставить работать код в вашем jsFiddle. Глядя на этот пост в блоге MSDN, мы находим, что postMessage
работает только между IFrames в более старых версиях IE, что еще не исправлено в IE 11.
Эта статья ссылается на демонстрацию проблемы. Есть несколько обходных путей, которые включают вызов скриптов на window.opener
, Однако, как говорится в этом блоге (выделение мое):
К сожалению, этот обходной путь часто невозможен, потому что политика того же источника требует, чтобы всплывающее окно и страница window.opener были из одного источника, чтобы вызывать функции сценариев друг друга.
Таким образом, похоже, что единственный способ сделать это - что-то вроде этого, когда ребенок размещается в IFrame в родительском элементе. Я создал подобную демонстрацию здесь, основываясь на коде в вашем. Это довольно просто, но отправляет сообщение на contentWindow
IFrame, который в свою очередь отвечает.
Я вижу рекомендацию использовать MessageChannel
вместо этого, но мне также интересно, стоит ли исследовать использование Web Workers, хотя их использование, конечно, будет зависеть от характера вашей задачи. Существует также ответ на этот вопрос, где использовался подход IFrame, но для его отображения использовался диалог пользовательского интерфейса jQuery - я думаю, вы могли бы сделать то же самое с модалами в Bootstrap, если вы предпочитаете это.
Для справки:
HTML
<iframe id="iframe" src="http://jsbin.com/iLapokOS/7/"></iframe>
<div id="log"></div>
<button id="post-message-button">Post message to window</button>
Родительский скрипт
var wnd;
$(document).ready(function() {
$('#log').append('listening...');
wnd = $('#iframe')[0].contentWindow;
window.addEventListener('message', function(e){
$('#log').append('<br/>Received message: ' + JSON.stringify(e.data));
}, false);
$('#post-message-button').click(function() {
if(!wnd){
return;
}
$('#log').append('<br/>sending...');
wnd.postMessage('Hello?', 'http://jsbin.com');
});
});
Детский HTML и JS
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<script>
$(document).ready(function() {
window.addEventListener("message", function(e){
$('body').append('<br/>Origin: ' + e.origin);
$('body').append("<br/>Received message: " + JSON.stringify(e.data));
e.source.postMessage('Hello yourself', e.origin);
}, false);
});
</script>
</body>
</html>
Обновление 16/01: действительно плохая часть заключается в том, что он действительно работает, даже если сообщение отправлено из того же домена, но после перенаправления другим доменом.
Весело, эта "функция безопасности" может использоваться в обратном порядке, чтобы полностью обойти ограничение междомена.
В родительском окне на example.com
:
<script>
window.open("http://example.com/dummy_redirect");
window.addEventListener('message', function(ev) {console.log(ev.data)})
</script>
На example.com
сервер:
GET /dummy_redirect 302 http://jsfiddle.net/b6yfbunw/
Всплывающее окно откроется в вашем домене, перенаправит на jsfiddle, и вызов postMessage будет работать в IE. Вы даже можете перейти к любому домену после этого и продолжать делать вызовы postMessage в родительское окно.
Есть несколько упоминаний о iframe
обходной путь, но я видел только отправку сообщения iframe
,
Вот пример получения сообщения от iframe
вместо:
Родительская страница (http://first-domain.com/receive-message.html)
<html>
<head>
<script>
window.addEventListener('message', console.log.bind(console, 'Got message:'));
</script>
</head>
<body>
<iframe src="http://second-domain.com/send-message.html"></iframe>
</body>
</html>
Дочерняя страница (http://second-domain.com/send-message.html)
<html>
<head>
<script>
window.parent.postMessage('hi there', '*');
</script>
</head>
<body></body>
</html>
Я обнаружил, что если я запускаю другое окно, запускаю свое окно, затем закрываю другое окно, тогда я могу нормально работать с моим окном.
vvWindow0 = window.open("http://apsed4065:8047/virtualviewer/index.html");
vvWindow = window.open("http://apsed4065:8047/virtualviewer/index.html");
vvWindow0.close(); <!-- to close the window -->
vvWindow.postMessage(message, 'http://apsed4065:8047');