带有iframe的Chrome扩展程序内容脚本“阻止了具有起源的框架访问跨域框架”

时间:2018-11-30 23:48:49

标签: iframe google-chrome-extension content-script

我浏览了一些与SO相关的问题和解决方案,但似乎都没有最新的解决方案或与我类似的问题。

所以这是基本问题。我有一个在https://example.com/*上运行的内容脚本,目的是更改页面上的HTML5 <video>播放器。但是,实际的播放器在iframe中。为了获得实际的HTMLMediaElement,我应该能够运行

document.querySelector("iframe").contentWindow.document.querySelector("video")

但是,此操作失败并显示错误

Uncaught DOMException: Blocked a frame with origin "https://example.com" from accessing a cross-origin frame.

有关其他信息,document.querySelector("iframe").src返回https://static.example.com/.../player.html。 “来源”不同,但与原始站点的根域相同。

所以我想知道如何使用内容脚本(或者,我猜其他方法)在iframe中操纵媒体播放器。


此扩展名大致如下。

manifest.json

{
    "manifest_version": 2,
    //...
    "permissions": ["activeTab", "storage", "https://example.com/*"],
    //...
    "content_scripts": [
        {
            "all_frames": true,
            "matches": [
                "https://example.com/*"
            ],
            "js": [
                "inject.js"
            ]
        }
    ],
    //...
}

inject.js

winndow.onload = () => {
    document
        .querySelector("iframe.video-player")
        .contentWindow.document
        .querySelector("video#player_html5_api");
};

更新

我不太确定为什么以前没有想到这一点,但是正如答案中提到的那样,将其视为完全不同的内容注入的关键。假设您不需要跨iframe边界进行任何交互(仍然可以通过消息传递来实现),则只需按以下方式修改清单即可。密钥与iframe的来源匹配,而不与页面的来源匹配。 “ all frames: true行是必不可少的,因为默认情况下,不是最顶部的帧将不匹配。

manifest.json

{
    //...
    "content_scripts": [
        {
            "all_frames": true,
            "matches": [
                "https://static.example.com/.../player.html"
            ],
            "js": [
                "inject.js"
            ]
        }
    ],
    //...
}

1 个答案:

答案 0 :(得分:1)

这里的重要要点来自于这句话:

  

有关更多信息,document.querySelector(“ iframe”)。src返回https://static.example.com/.../player.html。 “来源”不同,但与原始站点的根域相同。

来源不同。static.example.com!= example.com)即使根域相同,但来源不是 。 (这就是tuckerchapin.sketchyfreewebhost.com无法提供和修改j6m8.sketchyfreewebhost.com内容的原因)。因此,从理论上讲,这是“更好”的行为。

取自this answer

  如果要访问框架,

协议,主机名和端口必须与您的域相同。

(重点是我的)