我前几天做Chrome-EXT开发的时候,遇到一些坑。 Chrome扩展是有好几个沙盒环境一起协同工作的,如果你之前做过 IOS-WebView 的二次开发,应该有印象: JavaScript的注入,是有“World”概念的,默认是MAIN-World,这个就是网页的默认js执行环境。 然后还能自定义World,这种属于ISOLATED-World,和MAIN-World在同一个线程里面,但是内存是完全隔离的,类似于在一个独立的iframe环境中。
MAIN-World 有非常严格的安全限制。比如我就不能再MAIN-World里面去发起 ws://localhost 的链接。因为Google的网页非常注重安全,都会开启“内容安全协议限制”,比如不能Eval、new Function;以及MAIN-World的资源来源会有域名限制;甚至不可以和Chrome扩展的Servical-Worker通讯。
所以必须是这样的通讯路径: “网页脚本(MAIN-World) ⇄ content-script(ISOLATED-World) ⇄ background/service-worker” “网页脚本(MAIN-World) ⇄ content-script(ISOLATED-World) ⇄ backend-server/websocket”
以下是AI总结了一些区别:
content-script 到底有哪些“网页脚本做不到”的能力?
一句话:能跨域、能调扩展 API、能访问 Chrome 内部数据,但又不必暴露给页面。
具体列出来:
能力 | 页面脚本能否做到 | content-script 能否做到 | 备注 |
---|---|---|---|
访问任意扩展 API(chrome.runtime.sendMessage 、chrome.storage 、chrome.i18n …) | ❌ | ✅ | 页面脚本没有这些 API。 |
跨域请求(无视 CORS) | ❌ | ✅ | 只要在 manifest.json 里给 host 权限即可。 |
读取/修改 DOM,但不会被页面脚本看到(如果 Shadow DOM 方式注入) | 部分 | ✅ | 页面脚本无法直接访问 content-script 的变量。 |
注入到每一个匹配的页面,无需用户手动安装 | ❌ | ✅ | 只要 URL 匹配,扩展安装后自动注入。 |
在页面加载早期(document_start )就执行 | ❌ | ✅ | 可以抢在页面脚本之前跑。 |
通过 chrome.runtime.onMessage 与 background/popup 双向通讯 | ❌ | ✅ | 页面脚本没有 chrome.runtime 。 |
使用 chrome.runtime.getURL 拿到扩展内部资源(图片、wasm、worker) | ❌ | ✅ | 页面脚本拿不到 chrome-extension:// 的内部 URL。 |
在 Manifest V3 下,使用 chrome.scripting.executeScript 动态注入到任意标签 | ❌ | ✅ | 页面脚本无法调用扩展 API。 |
background service-worker 独有的“超能力”
能力 | 说明 |
---|---|
长期离线事件监听 | 浏览器冷启动后仍能监听 chrome.runtime.onInstalled / chrome.alarms / chrome.webRequest 等 |
无前台限制的网络请求 | 可跨域 fetch() 任意 URL(只要 host_permissions 里声明),不受 CORS 限制 |
webRequest/declarativeNetRequest | 拦截、修改、阻断整个浏览器的 HTTP 请求 |
管理浏览器级数据 | cookies、历史记录、书签、下载、代理设置、标签、窗口、扩展管理 |
后台定时任务 | chrome.alarms 可在浏览器重启后继续触发 |
native messaging | 与本地二进制程序建立长期双向通道 |
推送消息(GCM/FCM) | 接收云端推送,唤醒扩展 |
contextMenus | 右键菜单全局注册 |
** omnibox 关键字** | 地址栏关键字建议 |
chrome.storage.session | MV3 新提供的会话级存储,content-script 无法直接访问 |
chrome.scripting.executeScript | 动态向任意标签页注入脚本,无需在 manifest 声明静态 content-script |