‹Iframe› javascript доступ к родительской DOM через домены?

Я контролирую содержимое iframe, встроенного в страницу из другого домена. Есть ли способ для javascript в моем iframe вносить изменения в родительскую DOM?

Например, я хотел бы, чтобы мой скрипт iframed добавлял кучу элементов html в родительский DOM. Это кажется довольно сложной задачей - мысли?

Изменить: существует метод под названием "обмен сообщениями с идентификатором фрагмента", который может быть способом взаимодействия между междоменными фреймами iframe.

Изменить: Кроме того, Firefox 3.5, Opera, Chrome (и т. д.), похоже, принимают html5 api "postMessage", который обеспечивает безопасную междоменную передачу данных между фреймами, окнами iframe и всплывающими окнами. Он работает как система событий. IE8, по-видимому, поддерживает эту функцию, что, возможно, немного удивительно.

Резюме: Нет, вы не можете напрямую получить доступ к DOM страницы или изменить ее из другого домена. Но вы можете общаться с ним, и он может сотрудничать, чтобы вносить нужные вам изменения.


person aaaidan    schedule 18.08.2009    source источник
comment
В настоящее время принятый ответ был правильным в 2009 году, но времена изменились. Stefan Steiger's лучше, и, возможно, стоит изменить ваш принятый ответ на него.   -  person Quentin    schedule 08.06.2016
comment
Спасибо @Quentin, я учту это.   -  person aaaidan    schedule 08.06.2016


Ответы (5)


Ненавижу это говорить, но я на 99% уверен, что этого не происходит напрямую из соображений безопасности.

Вы можете попробовать это здесь.

бхх

person Andy Gaskell    schedule 18.08.2009
comment
Спасибо, эта ссылка очень хорошо демонстрирует проблему. - person aaaidan; 18.08.2009
comment
Что вы можете сделать, так это вернуть iframe в родительский домен из дочернего домена, и любые скрипты там могут получить доступ к parent.parent, потому что он находится в том же домене, это используется несколькими рекламными компаниями, которые попросят вас разместить файл ( внутренний iframe) на вашем сайте, чтобы они могли изменять размер объявлений. - person Hayden Crocker; 26.11.2013
comment
Пожалуйста, прочтите ответ @Stefan Steiger ниже. Вы можете общаться между фреймами с перекрестным происхождением, используя postMessage (). Конечно, вы должны владеть обоими доменами. - person Marco Panichi; 31.10.2017

Это возможно.

Вы правильно упомянули postMessage в своих правках. Для тех, кто ищет, есть отличный обратно-совместимый способ связи между доменами, использующий только javascript. А также короткий и простой код. Идеальное решение? Если вы можете запрашивать изменения в родительском и дочернем элементах:

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

person Kyle    schedule 23.11.2010

Да, ты можешь.
Вы можете реализовать window.postMessage для связи между фреймами и / или окнами между доменами.
Но вам нужно сделать это асинхронным способом.
Если вам это нужно синхронно, вам нужно реализовать оболочки для этих асинхронных методов.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title></title>

    <!--
    <link rel="shortcut icon" href="/favicon.ico">


    <link rel="start" href="http://benalman.com/" title="Home">

    <link rel="stylesheet" type="text/css" href="/code/php/multi_file.php?m=benalman_css">

    <script type="text/javascript" src="/js/mt.js"></script>
    -->
    <script type="text/javascript">
        // What browsers support the window.postMessage call now?
        // IE8 does not allow postMessage across windows/tabs
        // FF3+, IE8+, Chrome, Safari(5?), Opera10+

        function SendMessage()
        {
            var win = document.getElementById("ifrmChild").contentWindow;

            // http://robertnyman.com/2010/03/18/postmessage-in-html5-to-send-messages-between-windows-and-iframes/


            // http://stackoverflow.com/questions/16072902/dom-exception-12-for-window-postmessage
            // Specify origin. Should be a domain or a wildcard "*"

            if (win == null || !window['postMessage'])
                alert("oh crap");
            else
                win.postMessage("hello", "*");
            //alert("lol");
        }



        function ReceiveMessage(evt) {
            var message;
            //if (evt.origin !== "http://robertnyman.com")
            if (false) {
                message = 'You ("' + evt.origin + '") are not worthy';
            }
            else {
                message = 'I got "' + evt.data + '" from "' + evt.origin + '"';
            }

            var ta = document.getElementById("taRecvMessage");
            if (ta == null)
                alert(message);
            else
                document.getElementById("taRecvMessage").innerHTML = message;

            //evt.source.postMessage("thanks, got it ;)", event.origin);
        } // End Function ReceiveMessage




        if (!window['postMessage'])
            alert("oh crap");
        else {
            if (window.addEventListener) {
                //alert("standards-compliant");
                // For standards-compliant web browsers (ie9+)
                window.addEventListener("message", ReceiveMessage, false);
            }
            else {
                //alert("not standards-compliant (ie8)");
                window.attachEvent("onmessage", ReceiveMessage);
            }
        }
    </script>


</head>
<body>

    <iframe id="ifrmChild" src="child.htm" frameborder="0" width="500" height="200" ></iframe>
    <br />


    <input type="button" value="Test" onclick="SendMessage();" />

</body>
</html>

Child.htm

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title></title>

    <!--
    <link rel="shortcut icon" href="/favicon.ico">


    <link rel="start" href="http://benalman.com/" title="Home">

    <link rel="stylesheet" type="text/css" href="/code/php/multi_file.php?m=benalman_css">

    <script type="text/javascript" src="/js/mt.js"></script>
    -->

    <script type="text/javascript">
        /*
        // Opera 9 supports document.postMessage() 
        // document is wrong
        window.addEventListener("message", function (e) {
            //document.getElementById("test").textContent = ;
            alert(
                e.domain + " said: " + e.data
                );
        }, false);
        */

        // https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
        // http://ejohn.org/blog/cross-window-messaging/
        // http://benalman.com/projects/jquery-postmessage-plugin/
        // http://benalman.com/code/projects/jquery-postmessage/docs/files/jquery-ba-postmessage-js.html

        // .data – A string holding the message passed from the other window.
        // .domain (origin?) – The domain name of the window that sent the message.
        // .uri – The full URI for the window that sent the message.
        // .source – A reference to the window object of the window that sent the message.
        function ReceiveMessage(evt) {
            var message;
            //if (evt.origin !== "http://robertnyman.com")
            if(false)
            {
                message = 'You ("' + evt.origin + '") are not worthy';
            }
            else
            {
                message = 'I got "' + evt.data + '" from "' + evt.origin + '"';
            }

            //alert(evt.source.location.href)

            var ta = document.getElementById("taRecvMessage");
            if(ta == null)
                alert(message);
            else
                document.getElementById("taRecvMessage").innerHTML = message;

            // http://javascript.info/tutorial/cross-window-messaging-with-postmessage
            //evt.source.postMessage("thanks, got it", evt.origin);
            evt.source.postMessage("thanks, got it", "*");
        } // End Function ReceiveMessage




        if (!window['postMessage'])
            alert("oh crap");
        else {
            if (window.addEventListener) {
                //alert("standards-compliant");
                // For standards-compliant web browsers (ie9+)
                window.addEventListener("message", ReceiveMessage, false);
            }
            else {
                //alert("not standards-compliant (ie8)");
                window.attachEvent("onmessage", ReceiveMessage);
            }
        }
    </script>


</head>
<body style="background-color: gray;">
    <h1>Test</h1>

    <textarea id="taRecvMessage" rows="20" cols="20" ></textarea>

</body>
</html>

Здесь вы должны изменить дочерний элемент, чтобы он отправлял почтовые сообщения родителю. например в child.htm вы делаете

window.parent.postMessage("alert(document.location.href); document.location.href = 'http://www.google.com/ncr'", "*");

а в родительском вы делаете (в receiveMessage) eval(evt.data); Не то чтобы использование eval небезопасно, поэтому вместо этого вы должны передать перечисление и вызвать соответствующую функцию, которую нужно поместить на родительскую страницу.

person Stefan Steiger    schedule 31.05.2013
comment
Загрузка дочернего iframe не будет работать в смешанном режиме. Например, главная страница в https и дочерняя страница в iframe (http). - person lmiguelmh; 02.03.2016
comment
@lmiguelmh: http-страница не должна загружаться на https-странице. - person Stefan Steiger; 14.06.2018

Я предполагаю, что без прокси вы столкнетесь с проблемами безопасности. Прокси-серверы могут очень пригодиться. Вы можете попробовать один из них:

(1) прокси на основе PHP (будьте осторожны, между полезными ссылками много рекламы)

(2) прокси Apache .htaccess - просто создайте подкаталог proxy в своем домене и поместите туда .htaccess файл, содержащий:

RewriteEngine on
RewriteRule ^(.*)$ http://picasaweb.google.com/$1 [P,L] 

Поместите другое доменное имя вместо picasaweb.google.com

Лично я предпочитаю использовать прокси Apache

person warpech    schedule 19.08.2009
comment
Спасибо за ответ, варпеч. Я думаю, что мои правки запутали мой исходный вопрос, который спрашивал, как я могу изменить dom на родительской странице из iframe из другого домена. Короткий ответ кажется невозможным. Итак, сейчас я изучаю методы межкадрового взаимодействия, и прокси на стороне сервера, безусловно, один из них. Спасибо! - person aaaidan; 20.08.2009

Для AJAX сервер может вернуть заголовок Access-Control-Allow-Origin: *, чтобы разрешить междоменный доступ. Возможно, это также работает для IFRAME.

person user836773    schedule 10.07.2011