我在我的HTML页面中加载一个<iframe>,并试图使用JavaScript访问其中的元素,但当我尝试执行我的代码时,我得到以下错误:

阻止原点为“http://www.example.com”的帧访问跨原点帧。

如何访问框架中的元素?

我正在使用这段代码进行测试,但徒劳:

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

当前回答

同源策略

你不能访问一个<iframe>与不同的起源使用JavaScript,这将是一个巨大的安全漏洞,如果你可以这样做。对于同源策略,浏览器会阻止试图访问具有不同起源的帧的脚本。

如果地址中至少有以下部分未被维护,则认为来源不同:

protocol://hostname:port/...

如果要访问帧,协议、主机名和端口必须与您的域相同。

注意:众所周知,Internet Explorer并没有严格遵守这个规则,请参阅这里了解详细信息。

例子

下面是尝试从http://www.example.com/home/index.html访问以下url时会发生的情况

URL                                             RESULT
http://www.example.com/home/other.html       -> Success
http://www.example.com/dir/inner/another.php -> Success
http://www.example.com:80                    -> Success (default port for HTTP)
http://www.example.com:2251                  -> Failure: different port
http://data.example.com/dir/other.html       -> Failure: different hostname
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname

解决方案

尽管同源策略阻止脚本访问具有不同起源的站点的内容,但如果您拥有这两个页面,则可以使用window解决这个问题。postMessage和它的相关message事件在两个页面之间发送消息,如下所示:

In your main page: const frame = document.getElementById('your-frame-id'); frame.contentWindow.postMessage(/*any variable or object here*/, 'https://your-second-site.example'); The second argument to postMessage() can be '*' to indicate no preference about the origin of the destination. A target origin should always be provided when possible, to avoid disclosing the data you send to any other site. In your <iframe> (contained in the main page): window.addEventListener('message', event => { // IMPORTANT: check the origin of the data! if (event.origin === 'https://your-first-site.example') { // The data was sent from your site. // Data sent with postMessage is stored in event.data: console.log(event.data); } else { // The data was NOT sent from your site! // Be careful! Do not use it. This else branch is // here just for clarity, you usually shouldn't need it. return; } });

这个方法可以双向应用,也可以在主页面创建监听器,并从帧接收响应。同样的逻辑也可以在弹出窗口中实现,以及基本上由主页生成的任何新窗口(例如使用window.open()),没有任何区别。

禁用浏览器中的同源策略

关于这个主题已经有了一些很好的答案(我刚刚在谷歌上找到了它们),所以,对于可能的浏览器,我将链接相对答案。但是,请记住,禁用同源策略只会影响您的浏览器。此外,禁用同源安全设置的浏览器会允许任何网站访问跨源资源,所以这是非常不安全的,如果你不知道自己在做什么(例如开发目的),就不应该这样做。

谷歌Chrome Mozilla Firefox Safari Opera:与Chrome相同 Microsoft Edge:与Chrome相同 Brave:与Chrome相同 Microsoft Edge(旧的非铬版本):不可能 微软Internet Explorer

其他回答

补充Marco Bonelli的回答:当前框架/iframe之间的最佳交互方式是使用窗口。所有浏览器都支持的postMessage

当我试图嵌入一个iframe,然后用Brave打开网站时,我遇到了这个错误。当我把这个网站改为“盾牌下降”时,这个错误就消失了。显然,这并不是一个完整的解决方案,因为任何使用Brave访问网站的人都会遇到同样的问题。要真正解决这个问题,我需要做本页上列出的其他事情之一。但至少我现在知道问题出在哪里了。

实际上,在特定的情况下,有一个变通办法。

如果在同一个域上运行两个进程,但端口不同,那么两个Windows可以不受限制地交互。(即localhost:3000 & localhost:2000)。为了实现这一点,每个窗口都需要将它们的域更改为共享源:

document.domain = 'localhost'

这也适用于您正在使用同一二级域上的不同子域的场景,即您在john.site.example上试图访问peter.site.example或只是site.example

document.domain = 'site.example'

通过显式设置document.domain;浏览器将忽略主机名的差异,Windows可以被视为来自“同源”。现在,在父窗口中,你可以进入iframe:

如果你可以控制iframe的内容——也就是说,如果它只是在一个跨起源的设置中加载,比如在Amazon Mechanical Turk上——你可以用<body onload='my_func(my_arg)'>属性来规避这个问题。

例如,对于内部html,使用this html参数(yes -这是定义的,它引用内部主体元素的父窗口):

<身体onload = ' changeForm(这)>

在内部html:

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>

同源策略

你不能访问一个<iframe>与不同的起源使用JavaScript,这将是一个巨大的安全漏洞,如果你可以这样做。对于同源策略,浏览器会阻止试图访问具有不同起源的帧的脚本。

如果地址中至少有以下部分未被维护,则认为来源不同:

protocol://hostname:port/...

如果要访问帧,协议、主机名和端口必须与您的域相同。

注意:众所周知,Internet Explorer并没有严格遵守这个规则,请参阅这里了解详细信息。

例子

下面是尝试从http://www.example.com/home/index.html访问以下url时会发生的情况

URL                                             RESULT
http://www.example.com/home/other.html       -> Success
http://www.example.com/dir/inner/another.php -> Success
http://www.example.com:80                    -> Success (default port for HTTP)
http://www.example.com:2251                  -> Failure: different port
http://data.example.com/dir/other.html       -> Failure: different hostname
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname

解决方案

尽管同源策略阻止脚本访问具有不同起源的站点的内容,但如果您拥有这两个页面,则可以使用window解决这个问题。postMessage和它的相关message事件在两个页面之间发送消息,如下所示:

In your main page: const frame = document.getElementById('your-frame-id'); frame.contentWindow.postMessage(/*any variable or object here*/, 'https://your-second-site.example'); The second argument to postMessage() can be '*' to indicate no preference about the origin of the destination. A target origin should always be provided when possible, to avoid disclosing the data you send to any other site. In your <iframe> (contained in the main page): window.addEventListener('message', event => { // IMPORTANT: check the origin of the data! if (event.origin === 'https://your-first-site.example') { // The data was sent from your site. // Data sent with postMessage is stored in event.data: console.log(event.data); } else { // The data was NOT sent from your site! // Be careful! Do not use it. This else branch is // here just for clarity, you usually shouldn't need it. return; } });

这个方法可以双向应用,也可以在主页面创建监听器,并从帧接收响应。同样的逻辑也可以在弹出窗口中实现,以及基本上由主页生成的任何新窗口(例如使用window.open()),没有任何区别。

禁用浏览器中的同源策略

关于这个主题已经有了一些很好的答案(我刚刚在谷歌上找到了它们),所以,对于可能的浏览器,我将链接相对答案。但是,请记住,禁用同源策略只会影响您的浏览器。此外,禁用同源安全设置的浏览器会允许任何网站访问跨源资源,所以这是非常不安全的,如果你不知道自己在做什么(例如开发目的),就不应该这样做。

谷歌Chrome Mozilla Firefox Safari Opera:与Chrome相同 Microsoft Edge:与Chrome相同 Brave:与Chrome相同 Microsoft Edge(旧的非铬版本):不可能 微软Internet Explorer