多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Zotero Connectors迁移Manifest V3全记录:Offscreen Document、Service Worker与webRequestIntercept深度剖析

Zotero Connectors迁移Manifest V3全记录:Offscreen Document、Service Worker与webRequestIntercept深度剖析 Zotero Connectors迁移Manifest V3全记录Offscreen Document、Service Worker与webRequestIntercept深度剖析【免费下载链接】zotero-connectorsChrome, Firefox, Edge, and Safari extensions for Zotero项目地址: https://gitcode.com/gh_mirrors/zo/zotero-connectorsZotero Connectors 是 Zotero 官方的浏览器扩展支持 Chrome、Firefox、Edge、Safari能一键抓取网页题录、保存 PDF、拦截 CSL/RIS/BibTeX 文件导入。本文完整记录它从 Manifest V2 迁移到 Manifest V3 的全过程如何用Service Worker取代常驻后台页、如何用Offscreen Document给翻译器Translator补上缺失的 DOM 环境、以及webRequestIntercept如何从阻塞式拦截重构为声明式网络请求DNR方案。一、迁移背景两份 manifest 的差异项目同时维护两份清单文件构建时按目标浏览器二选一MV2 清单src/browserExt/manifest.jsonMV3 清单src/browserExt/manifest-v3.json对比两者核心差异一览维度Manifest V2Manifest V3后台background.scripts常驻后台页background.service_worker可被随时终止工具栏按钮browser_actionaction请求拦截webRequestBlocking阻塞式非阻塞webRequestdeclarativeNetRequestCSP允许unsafe-eval严格禁止 eval新增能力无offscreen权限 sandbox页面最低 Chrome 版本5588MV3 最大的破坏性变化是两点Service Worker 生命周期不可控浏览器可在 30 秒无活动后随时杀掉它和禁止 eval。Zotero Connectors 的迁移工作基本都围绕这两个问题展开。二、Service Worker从常驻后台到定时保活1. 入口脚本 background-worker.jsMV3 中 Service Worker 无法像 MV2 那样用多脚本声明因此项目用 src/browserExt/background-worker.js 作为唯一入口在顶部通过importScripts依次加载构建时注入的后台脚本、保活脚本和background.js并对启动异常做了兜底捕获因为 SW 启动失败几乎无法调试。2. keep-mv3-alive.js防止 Worker 被杀Service Worker 默认空闲即死但 Zotero 的抓题录、导入文件等流程都是跨消息的异步长流程中途被杀会导致功能中断。项目的对策见 src/browserExt/keep-mv3-alive.js每20 秒调用一次chrome.runtime.getPlatformInfo()一个轻量的心跳API 调用制造活动痕迹心跳最长持续10 分钟LET_DIE_AFTER到期后自动停跳避免无限占用资源是否续命由 src/browserExt/background.js 中的计数器_keepServiceWorkerAlive决定——长任务开始时setKeepServiceWorkerAlive(true)结束时递减用引用计数保证并行任务不会互相误杀 Worker。3. 状态持久化createMV3PersistentObjectMV2 后台页常驻tabInfo等状态放内存即可MV3 下 Worker 重启后内存清零。项目在 src/common/utilities.js 提供了createMV3PersistentObject返回一个深度 Proxy 对象任意属性被读写时自动序列化到browser.storage.session支持ignoreKeys选项跳过无法序列化的字段如回调函数后台初始化时用它重建每个标签页的状态createMV3PersistentObject(tabInfo, ...)Worker 重启后依然认得每个标签页抓到了什么。另有keepServiceWorkerAliveFunction工具同文件 L120-L132把任意异步函数包装为执行前续命、完成后释放的安全版本供 Google Docs 集成等长耗时请求使用。三、Offscreen Document给翻译器一个 DOM家1. 为什么需要 Offscreen DocumentZotero 的翻译器本质上是在DOM 环境里解析网页并抽取题录查找meta标签、调用 JS DOM API。而 MV3 的 Service Worker没有 DOMMV2 时代直接在后台页里跑翻译的逻辑在 MV3 中无处安放。Chrome 为此提供了 Offscreen Document API——一个不显示在界面上的隐藏页面允许扩展在其中使用 DOM。2. 三层架构offscreen → sandbox → 翻译器MV3 严格禁止 evalCSP 中没有unsafe-eval而部分翻译器代码需要动态执行因此项目设计了一个巧妙的三层结构Service Worker (background-worker.js) └── OffscreenManager (后台消息调度) │ MessageChannel 端口 ▼ offscreen.htmlOrchestrator不允许 eval └── iframe srcoffscreenSandbox.html ← 声明在 manifest 的 sandbox 字段 └── 翻译器在此运行沙箱 iframe 允许 eval各层职责管理端src/browserExt/background/offscreenManager.js 中的Zotero.OffscreenManager负责创建/销毁离屏页。首次使用时调用browser.offscreen.createDocument理由声明为reasons: [DOM_PARSER]、justification: Scraping the document with Zotero Translators还负责在 Service Worker 重启后通知离屏页重建消息通道并每 15 分钟清理已关闭标签页的翻译实例防止内存泄漏。编排端src/browserExt/offscreen/offscreen.html 极简只加载 offscreen.js等待沙箱 iframe 就绪后通过MessageChannel把端口postMessage给 Service Worker完成三方握手若 Worker 被重启则自动重新初始化service-worker-restarted消息。沙箱端offscreenSandbox.html在 MV3 清单中声明于sandbox.pages字段manifest-v3.json L53-L55浏览器允许沙箱页面使用 eval。offscreenSandbox.js 在此初始化消息 API 并启动Zotero.OffscreenTranslate真正执行翻译逻辑。3. VirtualOffscreenTranslate把远程调用伪装成本地对象内容脚本侧的改动同样精彩。src/browserExt/inject/virtualOffscreenTranslate.js 用 Proxy 实现了一个虚拟翻译器内容脚本照常写translate.getTranslators()、translate.translate()Proxy 拦截后全部转成消息Translate.new、Translate.setDocument等经后台转发给离屏沙箱连MutationObserver监听 DOM 变化这类细节都做了双向桥接。对上层代码来说翻译从同进程执行变成了跨进程 RPC但 API 签名完全不变。四、webRequestIntercept从阻塞拦截到声明式规则1. 放弃 blocking拥抱只读监听MV2 的核心能力webRequestBlocking允许扩展同步修改、重定向甚至取消请求MV3 将其移除。src/browserExt/webRequestIntercept.js 的init中有一行关键代码let useBlocking !Zotero.isManifestV3 !Zotero.isSafari;即 MV3 下所有监听器都退化为只读观察者onBeforeSendHeaders记录请求头、onHeadersReceived解析响应头、onErrorOccurred/onCompleted清理元数据。监听器返回值的重定向/取消逻辑在handleRequest末尾被明确屏蔽L143-L145——MV3 中返回值不再生效。这套机制依然支撑着两个核心体验PDF 子框架保存offerSavingPDFInFrameL77-L87通过响应头content-type: application/pdf识别嵌入 PDF弹出保存提示文件类型拦截见下文。2. DNR 会话规则改写请求头的替代方案需要修改请求头的场景如发送 Cookie 给 Zotero 服务器MV3 的解法是declarativeNetRequest动态会话规则见 replaceHeadersDNR动态生成一条modifyHeaders规则用随机ruleID标识仅对扩展自身发起的xmlhttprequest生效规则激活期间调用setKeepServiceWorkerAlive(true)防止 Worker 被杀60 秒后自动清理规则并释放保活还顺手规避了 Chrome 的一个 bugcookie头名必须小写才能通过append操作的白名单校验。3. 静态 DNR 规则拦截 CSL 样式导入识别到 .csl/.ris/.bib 文件自动提示导入这类重定向类拦截MV3 要求规则在请求前就存在不能运行时动态插入因此采用了静态规则文件方案规则定义在 src/browserExt/styleInterceptRules.json用正则把zotero.org/styles/xxx、GitHub/Gitee 上的.csl原始文件地址重定向回原页面并追加#importConfirm锚点清单中通过declarative_net_request.rule_resources静态注册该文件manifest-v3.json L18-L24后台的 contentTypeHandler.js 通过mv3CSLWhitelistRegexp白名单正则监测标签页 URL一旦检测到带#importConfirm的样式页自动执行样式导入或按用户选择跳回原始 URL。一个静态重定向 URL 白名单监测的组合优雅地补回了 MV2 阻塞重定向丢失的能力。五、构建体系一份代码三种发行gulpfile.js 定义了manifestv3/firefox/safari三个构建目标构建时把manifest.json与manifest-v3.json互换、按目标注入browser-polyfill.js、background.js与background-worker.js等差异脚本最终在build/browserExt产出各浏览器可用版本。开发者只需克隆仓库后执行npm install再运行构建脚本即可本地加载测试。六、总结MV3 迁移的三大设计模式MV3 限制Zotero 的对策关键文件Worker 会休眠心跳保活 引用计数续命 session 存储持久化keep-mv3-alive.js、utilities.js无 DOM / 禁 evalOffscreen Document 三层结构 沙箱 iframeoffscreenManager.js、offscreen.js无阻塞 webRequest只读监听 DNR 静态/会话规则webRequestIntercept.js、styleInterceptRules.json这套方案证明了MV3 虽然收回了扩展的超能力但通过 Offscreen Document、会话级 DNR 规则和 Proxy 持久化等组合拳复杂扩展依然可以平滑演进而不牺牲用户体验。对于正在做类似迁移的扩展开发者Zotero Connectors 的源码是一份值得逐行研读的实战范本。【免费下载链接】zotero-connectorsChrome, Firefox, Edge, and Safari extensions for Zotero项目地址: https://gitcode.com/gh_mirrors/zo/zotero-connectors创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表