用Chrome扩展拦截和替换web应用程序中的图像



我正在尝试编写一个chrome扩展(供个人使用)来交换/替换由网页加载的图像。我用chrome浏览器工作了一段时间。webRequest,但我试图使它与manifest v3同步。

我的一般解决方案是,我在我自己的服务器上托管我的替换图像,包括一个脚本来检索json这样的图像列表。我获取该列表,并为每个图像创建一个动态重定向规则,使用chrome. declarativentrequest . updatedynamicrules。

如果我请求在主框架中替换图像,这一切都工作得很漂亮。我可以看到与onRuleMatchedDebug侦听器的成功匹配,并且(当然)路径被忠实地重定向。

然而,当我加载web应用程序,反过来加载图像(与javascript,大概与xmlhttprequest?),重定向规则不触发。启动器(一个javascript源文件)与被替换的图像在相同的域和相似的路径上。

//manifest.json
{
"name": "Image replace",
"description": "Replace images in web app",
"version": "2.0",
"manifest_version": 3,
"background": {"service_worker": "background.js"},
"permissions": [
"declarativeNetRequestWithHostAccess",
//  "declarativeNetRequestFeedback" // Not necessary once tested
],
"host_permissions" : [
//    "https://domain1.com/outerframe/*", // Not necessary
"https://domain2.com/innerframe/*",
"https://domain3.com/*",
"https://myexample.com/*"
]
}
// background.js
//chrome.declarativeNetRequest.onRuleMatchedDebug.addListener((info) => console.log(info)); // Not necessary once tested
var rules = [];
var idx = 1;
fetch("https://myexample.com/list") // returns json list like: ["subdir1/image1.png", "subdir1/image2.png", "subdir2/image1.png"]
.then((response) => response.json())
.then((data) => {
console.log(data);
for (const path of data) {
var src = "https://domain2.com/innerframe/v*/files/" + path; // wildcards a version number
var dst = "https://myexample.com/files/" + path;
rules.push({
"id" : idx++,
"action" : {
"type": "redirect",
"redirect": {
"url": dst
}
},
"condition" : {
"urlFilter": src,
// In the end I only needed main_frame, image, and not xmlhttprequest
"resourceTypes": ["main_frame", "image"]
}
});
}
chrome.declarativeNetRequest.updateDynamicRules({"addRules": rules, "removeRuleIds" : rules.map(r => r.id)});
});

再次,这一切都工作,如果我加载源图像直接在chrome中,但失败时,它被javascript应用程序加载。

我还尝试通过使用testMatchOutcome指定适当的启动器来测试匹配,但是我的浏览器似乎声称这个API不存在。我完全不知道这里出了什么问题。

// snippet attempted after above updateDynamicRules call
chrome.declarativeNetRequest.testMatchOutcome({
"initiator": "https://domain2.com/innerframe/files/script.js",
"type": "xmlhttprequest",
"url": "https://domain2.com/innerframe/v001/files/subdir/image1.png"
}, (outcome) => console.log(outcome)); 

我希望重定向到"https://myexample.com/files/subdir/image1.png"相反,我得到这个错误:Uncaught (in promise) TypeError: chrome. declarativentrequest . testmatchoutcome is not a function

文档https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#method-testMatchOutcome说它支持chrome 103+。我正在运行chrome 108.0.5359.72

谢谢!

编辑:示例代码更新以反映我下面的回答。

我已经设法弄清楚为什么直接请求被重定向,而脚本加载的请求没有。我的问题是启动器和主机权限。我一直依靠Chrome开发工具来提供启动器,在上面的例子中,它起源于domain2.com。然而,我需要的实际主机权限来自第三个域(称为domain3.com),这似乎是从domain2.com加载脚本的内容来源。

当我回忆起主机权限允许">"时,我发现了这一点,从长远来看,这不是一个好主意,但它确实允许重定向完成。从那里,我的onRuleMatchedDebug侦听器可以触发并将重定向的特征记录到控制台,这显示了我缺少的正确的启动器。

对我需要的重定向有了一个简明的视图,我现在可以截断这些选项中的一些,只留下实际需要的选项(在原始问题中编辑)。

之后,我想回头看看开发人员工具中的HTTP请求,并检查Referer头,它也有我需要的。

所以,除了愚蠢的疏忽之外,我想把这个问题留一段时间,以防有人知道为什么Chrome . declarativetrequest . testmatchoutcome在Chrome 108.0.5359.72中似乎不可用,但记录为103+。我把它归咎于文档是错误的,但似乎这个函数必须在某个时候发货,不知何故被错误地删除?除非有任何见解,我可能会把它作为一个bug提交。

最新更新