【问题标题】:<iframe> javascript access parent DOM across domains?<iframe> javascript 跨域访问父 DOM?
【发布时间】:2010-11-20 11:30:49
【问题描述】:

我控制嵌入在另一个域的页面中的 iframe 的内容。我的 iframe 中的 javascript 有什么方法可以更改父级的 DOM?

例如,我想让我的 iframed 脚本将一堆 html 元素添加到父 DOM。这似乎是一项艰巨的任务 - 想法?

编辑:存在一种称为“Fragment ID Messaging”的技术,它可能是跨域 iframe 之间通信的一种方式。

编辑:此外,Firefox 3.5、Opera、Chrome(等)似乎正在采用 html5 "postMessage" api,它允许在框架、iframe 和弹出窗口之间进行安全的跨域数据传输。它就像一个事件系统。显然,IE8 支持此功能,这可能有点令人惊讶。

总结:不,您不能直接访问/编辑来自另一个域的页面的 DOM。但是你可以与它交流,它可以合作做出你想要的改变。

【问题讨论】:

  • 目前接受的答案在 2009 年是正确的,但时代变了。 Stefan Steiger 的更好,可能值得更改您接受的答案。
  • 谢谢@Quentin,我会考虑的。

标签: javascript dom iframe cross-domain


【解决方案1】:

不想这么说,但我 99% 确定这不会因为安全而直接发生。

你可以试试here

【讨论】:

  • 谢谢,该链接很好地说明了问题。
  • 你可以做的是让一个 iframe 从子域返回到父域,并且那里的任何脚本都可以访问 parent.parent 因为它在同一个域上,这被一些广告公司使用将要求您在您的网站上托管一个文件(内部 iframe),以便他们调整添加的大小。
  • 请阅读下面@Stefan Steiger 的回答。您可以使用postMessage() 在跨源帧之间进行通信。当然,您必须同时拥有这两个域。
【解决方案2】:

有可能。

您在编辑中提到 postMessage 是对的。对于那些寻找的人来说,有一种很好的向后兼容的、仅限 javascript 的跨域通信方式。简短、简单的代码也是如此。完美解决方案?只要您可以请求修改父子节点:

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

【讨论】:

    【解决方案3】:

    是的,你可以。
    您可以实现 window.postMessage 以跨域跨 iframe 和/或窗口进行通信。
    但是您需要以异步方式执行此操作。
    如果您需要同步,则需要围绕这些异步方法实现包装器。

    <!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 是不安全的,因此您将改为传递一个枚举,并调用您需要放在父页面上的相应函数。

    【讨论】:

    • 子 iframe 的加载在混合模式环境中不起作用。例如,https 中的主页面和 iframe (http) 中的子页面。
    • @lmiguelmh:http 页面首先不应加载到 https 页面中。
    【解决方案4】:

    我猜你会在不使用代理的情况下遇到安全问题。代理可以非常好用。您可以尝试其中一种:

    (1)PHP based proxy(注意有用链接之间有很多广告)

    (2) Apache .htaccess 代理 - 只需在您的域中创建一个子目录 proxy 并在其中放置一个包含以下内容的 .htaccess 文件:

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

    用其他域名代替 picasaweb.google.com

    我个人更喜欢使用 Apache 代理

    【讨论】:

    • 感谢您的回答,warpech。我认为我的编辑混淆了我最初的问题,即询问如何从另一个域的 iframe 中更改父页面上的 dom。简短的回答似乎是“你不能”。所以我现在正在探索帧间通信方法,服务器端代理肯定是其中之一。谢谢!
    【解决方案5】:

    对于 AJAX,服务器可以返回标头 Access-Control-Allow-Origin: * 以允许跨域访问。也许它也适用于 IFRAME。

    【讨论】:

      猜你喜欢
      • 2011-10-03
      • 2014-01-17
      • 2012-04-05
      • 1970-01-01
      • 2013-03-05
      • 1970-01-01
      • 2010-11-21
      • 2010-10-16
      相关资源
      最近更新 更多