Изменение URL родительского окна из IFrame
У меня есть ситуация, когда у меня есть веб-приложения на двух разных серверах, где App1 содержит App2 в IFrame. Любые ссылки в App2 могут иметь атрибут target="_parent"
, который позволяет этим ссылкам открываться в верхнем окне. Тем не менее, я не могу найти способ получить такое же поведение в Javascript. Я нашел эту страницу, в которой утверждается, что дочерний фрейм может вызывать javascript в родительском фрейме с помощью parent.foo()
, но это не похоже на работать в IE8 или FF3.5. Я нашел этот вопрос SO, в котором объясняется, как работает эта модель безопасности. Но кажется странным, что я не могу сделать в Javascript то, что я могу сделать с простым тегом <a>
. Есть ли какое-либо обходное решение для этого? Я знаю о window.postMessage, но (насколько я знаю ) это работает только в Firefox.
Пример
server1/test.html
<html>
<head>
<script type="text/javascript">
function myCallback(foo) {
alert(foo);
}
</script>
</head>
<body>
<iframe src="http://server2/test2.htm" width="400" height="150"></iframe>
</body></html>
server2/test2.html
<html><body>
<script>
function clickit() {
parent.document.location = "http://www.google.com"; //not allowed
parent.myCallback("http://www.google.com"); //not allowed
}
</script>
<p>This should be in an iFrame!</p>
<p><a href="#" onclick="location.href='http://www.google.com'; return false;" target="_parent">normal link (works)</a></p>
<p><a href="javascript:clickit()">javascript link</a></p>
</body></html>
Ответы
Ответ 1
ОК. Я сделал больше исследований, и кажется, что postMessage работает во всех современных браузерах, даже IE (с предостережением, что IE имеет несколько другой способ сделать это). Вот как я получил его на работу (протестирован на WinXP в IE8, FF3.5, Chrome 3.0, Safari 4 beta, Opera 9.64):
server1/test.html
<html>
<head>
<script type="text/javascript">
if(navigator.appName == "Microsoft Internet Explorer")
window.attachEvent("onmessage", receiveMessage);
else
window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) {
if(e.origin == "http://server2") //important for security
if(e.data.indexOf('redirect:') == 0)
document.location = e.data.substr(9);
}
</script>
</head>
<body>
<iframe src="http://server2/test2.htm" width="400" height="150"></iframe>
</body>
</html>
server2/Test2.htm
<html><body>
<script>
function clickit() {
parent.postMessage('redirect:http://www.google.com', 'http://server1');
}
</script>
<p>This should be in an iFrame!</p>
<p><a href="http://www.google.com" target="_parent">normal link</a></p>
<p><a href="javascript:clickit()">javascript link</a></p>
</body></html>
Ответ 2
Простая вещь, которую вы можете сделать, это:
выполнить следующее из кода JavaScript на странице iframe
top.location = "https://www.google.co.in/";
это изменит расположение URL-адреса окна на https://www.google.co.in/
.
Еще одна вещь. Эта стратегия также может быть полезна, когда вы не хотите, чтобы кто-то мог переместить ваш сайт
просто напишите вышеуказанный код в готовой части документа.
Ответ 3
Нет, и не зря. Если вам это нужно, вы должны запустить все коммуникации через один из двух серверов; например, сервер1 действует как прокси для всех запросов для "server2/test2.html".
Ответ 4
Если оба родителя и iframe находятся на поддоменах в одном домене, вы можете что-то сделать с помощью свойства document.domain
. Если оба тела и iframe рассматриваются как имеющие одно и то же происхождение, изменение местоположения должно быть возможным; Я сам этого не пробовал. Некоторое чтение здесь
Ответ 5
Если кадры находятся в одном домене, вы должны иметь доступ к родительскому фрейму. В противном случае это проблема безопасности.
Единственное временное решение, которое приходит на ум, - использовать AJAX для обновления файла на каждом из серверов, а затем проверить содержимое противоположной файловой серверной части. Вы можете сделать то же самое, используя единую базу данных, если вы разрешаете подключения из внешних доменов.
Это все-таки избыток, хотя вы можете просто выставить ссылку в фрейме и сообщить пользователям, чтобы он нажал его, чтобы продолжить.