我需要在我的 Chrome 扩展程序中将我的 Service Worker 定义为持久的,因为我使用 webRequest API 来拦截在表单中为特定请求传递的一些数据,但我不知道如何做到这一点。我已经尝试了所有方法,但我的 Service Worker 一直在卸载。
如何保持加载并等待请求被拦截?
我需要在我的 Chrome 扩展程序中将我的 Service Worker 定义为持久的,因为我使用 webRequest API 来拦截在表单中为特定请求传递的一些数据,但我不知道如何做到这一点。我已经尝试了所有方法,但我的 Service Worker 一直在卸载。
如何保持加载并等待请求被拦截?
在您的情况下,它可能是 ManifestV3,https ://crbug.com/1024211 中的一个错误:工作人员不会因 webRequest 事件而醒来。所以只要使用 ManifestV2 直到它被修复,因为没有持久化服务工作者这样的东西。
防止扩展的 Service Worker 卸载的解决方法:
waitUntil
示例 1,硬编码超时:
self.onactivate = e => {
e.waitUntil(new Promise(resolve => setTimeout(resolve, 5 * 60e3)));
};
示例 2,等待Promise:
let allDone;
self.onactivate = e => e.waitUntil(new Promise(r => { allDone = r; })));
//................
chrome.some.event.addListener(() => {
foo().bar().finally(allDone);
});
从任何选项卡的内容脚本或从扩展程序的另一个页面(如弹出页面)打开运行时端口。此端口将持续五分钟(服务工作者的固有限制),因此您必须使用计时器和端口的 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 },
function: () => chrome.runtime.connect({ name: 'keepAlive' }),
// `function` will become `func` in Chrome 93+
});
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 团队意识到既定事实,即许多扩展可能需要在任意时间段内使用持久性后台脚本,并且至少有一个这样的扩展可能会被大多数扩展用户安装。
如果我理解正确,您可以通过警报唤醒服务工作者(background.js)。看下面的例子:
"permissions": [
"alarms"
],
chrome.alarms.create({ periodInMinutes: 4.9 })
chrome.alarms.onAlarm.addListener(() => {
console.log('log for debug')
});
不幸的是,这不是我的问题,可能你也有不同的问题。当我刷新 dev 扩展或停止并运行 prod 扩展时,Service Worker 完全死了。当我关闭并打开浏览器时,worker 不会运行,worker 中的任何侦听器也不会运行它。它尝试手动注册工人。例如:
// override.html
<!DOCTYPE html>
<html lang="en">
<head>...<head>
<body>
...
<script defer src="override.js"></script>
<body>
<html>
// override.js - this code is running in new tab page
navigator.serviceWorker.getRegistrations().then((res) => {
for (let worker of res) {
console.log(worker)
if (worker.active.scriptURL.includes('background.js')) {
return
}
}
navigator.serviceWorker
.register(chrome.runtime.getURL('background.js'))
.then((registration) => {
console.log('Service worker success:', registration)
}).catch((error) => {
console.log('Error service:', error)
})
})
这个解决方案部分帮助了我,但没关系,因为我必须在不同的选项卡上注册工人。可能有人知道决定。我会很高兴。
WebSocket
从chrome.runtime
我的扩展服务工作者的侦听器注册中注册的回调不会被调用,这听起来几乎是相同的问题。
我通过向它添加以下代码来确保我的服务工作者永不结束来解决这个问题:
function keepServiceRunning() {
setTimeout(keepServiceRunning, 2000);
}
keepServiceRunning()
在此之后,我的回调现在按预期调用。