我已经浏览了一些关于 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");
};
更新:
我不太确定为什么我之前没有想到这一点,但正如答案中提到的,将其视为完全不同的内容注入(inject)的关键。假设您不需要跨 iframe 边界的任何交互(仍然可以通过消息传递来实现),您只需修改 list 如下。关键是匹配 iframe 的来源,而不是页面的来源。 "
all frames: true
行是必不可少的,因为默认情况下不会匹配不是最顶层的帧。manifest.json
{
//...
"content_scripts": [
{
"all_frames": true,
"matches": [
"https://static.example.com/.../player.html"
],
"js": [
"inject.js"
]
}
],
//...
}
最佳答案
这里的重要内容来自这句话:
For additional information document.querySelector("iframe").src returns https://static.example.com/.../player.html. The "origin" is different, but is the same root-domain of the original site.
起源不同。 (
static.example.com
!= example.com
) 即使根域相同,但起源却不同。 (这就是为什么 tuckerchapin.sketchyfreewebhost.com 无法提供和修改来自 j6m8.sketchyfreewebhost.com 的内容)。因此,从理论上讲,这是“更好”的行为。取自 this answer :
Protocol, hostname and port must be the same of your domain, if you want to access a frame.
(强调我的)
关于iframe - 带有 iframe "blocked a frame with origin from accessing a cross-origin frame"的 Chrome 扩展内容脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53566431/