我正在编写 Chrome 扩展(manifest v3),主要目的是覆盖一些 Window 本机函数并在任何其他网页脚本可以访问它们之前替换它们。
我有
contentscript.js
,它有run_at = document_start
。 contentscript.js
成功地将我的script.js
注入到网页DOM中,或者注入<html>
或<head>
标签(通过突变观察者)。但是(!)我不能强制并保证我的script.js
将在任何其他网站之前首先运行脚本。
当我调试
contentscript.js
时,页面的DOM仅包含<html>
和我新注入的加载<script>
的script.js
元素。因此 run_at
工作得很好。但是,当我在最后一行之后使用调试器时,我不是进入 script.js
,而是进入网站脚本(即使我的 script.js 引用是标题中所有其他引用之上的第一个)。如果 contentscript.js 可以直接写入网页,那么一切就很容易解决了window
,但它不能。
我尝试在
contentscript.js
中添加变异观察器,我能够检测到 DOM 中添加的标签,并且我能够编辑/删除它们而不(?)让它们执行,但我需要页面工作。
我尝试过的:
debugger;
命令添加到任何 <script>
中,这样我就可以看到哪个脚本首先运行
-- 每次都是网站脚本,不是我的。async=false
、defer=false
-- 失败,<script>
来禁用它们,然后在我的 script.js
注册为已读后重新运行它们。我正在重新启用脚本,以便观察者观察脚本(a)或(b)通过 document.querySelectorAll 中的 DOM 顺序观察脚本。这种方法适用于某些网站,但有些网站会在“不存在的对象引用”上抛出错误,然后当我在控制台中检查它们时,这些错误都会被定义——对我来说,这似乎很奇怪,因为我按顺序评估原始脚本并且看起来像一些网站作者的竞争条件(?)。编辑:我还尝试使用直接
<script>
添加自定义 script.text = ... code ...
但这被拒绝,因为 CSP 需要哈希、随机数或不安全内联(但是,我将尝试编辑 HTTP 标头以包含现在不安全内联)。
是否有希望让我的脚本在有保证的情况下首先运行? 谢谢你
您的内容脚本无法直接写入网页的窗口对象的原因是由于执行世界。默认情况下,内容脚本在“孤立的世界”中工作,这意味着它们无法直接修改主网页上下文中的对象。 要直接写入网页的
window
(主世界),您需要将脚本注入主世界。
第一个解决方法:通过manifest.json注入脚本manifest.json
中指定来将内容脚本配置为在主世界中运行:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["src/my_content_script.js"],
"run_at": "document_start",
"world": "MAIN"
}
]
第二种解决方法:通过来自孤立世界的内容脚本将脚本元素注入到 DOM 中
contentScript.js:
const scriptEl = document.createElement("script");
scriptEl.type = 'module'; // Use 'module' if you're working with ES modules
scriptEl.src = chrome.runtime.getURL('./main-world.js');
(document.head || document.documentElement).appendChild(scriptEl);
现在,您可以直接写入网页的
window
// Example: It will directly modify the alert function of the webpage window
const alertFn = window.alert;
window.alert = function(msg) {
console.log(msg); // Do something with the message
alertFn(msg); // Pass the message to the original alert
};