我需要在 Chrome 扩展程序中将我的 Service Worker 定义为持久性,因为我使用 webRequest API 来拦截在表单中为特定请求传递的一些数据,但我不知道如何做到这一点。我已经尝试了所有方法,但我的 Service Worker 一直在卸载。
如何保持加载并等待请求被拦截?
答案 0 :(得分:6)
在您的情况下,这可能是 ManifestV3 中的一个错误,https://crbug.com/1024211:工作人员不会因 webRequest 事件而醒来。所以只要使用 ManifestV2 直到它被修复,因为没有持久化服务工作者这样的东西。
防止扩展的 Service Worker 卸载的解决方法:
waitUntil
示例 1,硬编码超时:
self.onactivate = e => {
e.waitUntil(new Promise(resolve => setTimeout(resolve, 5 * 60e3)));
};
示例 2,等待承诺:
let allDone;
self.onactivate = e => e.waitUntil(new Promise(r => { allDone = r; })));
//................
chrome.some.event.addListener(() => {
foo().bar().finally(allDone);
});
从任何选项卡的 runtime 或扩展程序的另一个页面(如弹出页面)打开 content script 端口。此端口将持续五分钟(Service Worker 的固有限制),因此您必须使用计时器和端口的 onDisconnect 事件再次与某个随机选项卡重新连接。
缺点:
<all_urls>
或 *://*/*
),将大多数扩展程序放入网上商店的慢速审核队列。实现示例:
manifest.json,相关部分:
"permissions": ["scripting"],
"host_permissions": ["<all_urls>"],
"background": {"service_worker": "bg.js"}
后台服务工作者 bg.js:
let lifeline;
keepAlive();
chrome.runtime.onConnect.addListener(port => {
if (port.name === 'keepAlive') {
lifeline = port;
setTimeout(keepAliveForced, 295e3); // 5 minutes minus 5 seconds
port.onDisconnect.addListener(keepAliveForced);
}
});
function keepAliveForced() {
lifeline?.disconnect();
lifeline = null;
keepAlive();
}
async function keepAlive() {
if (lifeline) return;
for (const tab of await chrome.tabs.query({ url: '*://*/*' })) {
try {
await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: () => chrome.runtime.connect({ name: 'keepAlive' }),
});
chrome.tabs.onUpdated.removeListener(retryOnTabUpdate);
return;
} catch (e) {}
}
chrome.tabs.onUpdated.addListener(retryOnTabUpdate);
}
async function retryOnTabUpdate(tabId, info, tab) {
if (info.url && /^(file|https?):/.test(info.url)) {
keepAlive();
}
}
打开一个带有扩展页面的新标签页,例如chrome.tabs.create({url: 'bg.html'})
。
它将具有与 ManifestV2 的持久背景页面相同的功能,但 a) 它是可见的,并且 b) 无法通过 chrome.extension.getBackgroundPage
(可以用 chrome.extension.getViews 替换)访问。
缺点:
您可以通过向页面添加信息/日志/图表/仪表板来让您的用户更容易忍受,还可以添加 beforeunload
侦听器以防止标签被意外关闭。
让我们希望 Chromium 能够提供一个 API 来控制这种行为,而无需诉诸此类肮脏的黑客和可悲的解决方法。同时,在 crbug.com/1152255 中描述您的用例(如果尚未在此处进行描述)以帮助 Chromium 团队了解既定事实,即许多扩展可能需要在任意时间段内使用持久性后台脚本,并且至少有一个这样的扩展程序可能由大多数扩展程序用户安装。
答案 1 :(得分:0)
WebSocket
侦听器注册中注册的 chrome.runtime
回调不会被调用,这听起来几乎是相同的问题。
我通过添加以下代码来确保我的服务工作者永不结束来解决这个问题:
function keepServiceRunning() {
setTimeout(keepServiceRunning, 2000);
}
keepServiceRunning()
在此之后,我的回调现在按预期调用。