最近在做一个https网站与局域网设备服务器通信的浏览器插件,用于转发https到http,代理websocket。研究了一下插件的通信。
✅ 简明回答:content.js
和 background.js
的通信方式有两种
通信方式 | 是否双向 | 是否长连接 | 适用场景 |
---|---|---|---|
chrome.runtime.sendMessage / onMessage | ✅单次请求-响应 | ❌短连接(一次性) | 简单、一次性的请求 |
chrome.runtime.connect / onConnect + port.postMessage | ✅双向 | ✅支持持久长连接 | 需要持续通信,如大文件、WebSocket代理、流式传输等 |
🧩 1. chrome.runtime.sendMessage
/ chrome.runtime.onMessage
作用:
发送一次性消息(请求 -> 响应)
示例:
content.js
发消息到 background.js
chrome.runtime.sendMessage({ type: "ping" }, (response) => {
console.log("收到 background 响应:", response);
});
background.js
中接收:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === "ping") {
sendResponse({ reply: "pong from background" });
}
return true; // 保持异步响应有效
});
✅ 适合: 请求设备状态、获取 token、简单查询等。
🔁 2. chrome.runtime.connect
/ onConnect
+ port.postMessage
作用:
建立持久连接,可用于持续数据交互,如:
- 分片上传大文件
- WebSocket 代理中转
- 实时日志或状态推送
示例:
content.js
中发起连接:
const port = chrome.runtime.connect({ name: "toocaa-page" });
port.postMessage({ type: "file-chunk", data: ... });
port.onMessage.addListener((msg) => {
console.log("收到 background 推送:", msg);
});
background.js
中监听连接:
chrome.runtime.onConnect.addListener((port) => {
if (port.name === "toocaa-page") {
port.onMessage.addListener((msg) => {
if (msg.type === "file-chunk") {
// 收到文件片段
}
// 发送响应或推送消息
port.postMessage({ type: "upload-status", progress: "50%" });
});
}
});
✅ 适合: 文件流、持续上传、插件与网页实时交互。
❗重要提醒:
区别总结:
特性 | sendMessage | connect / port |
---|---|---|
连接生命周期 | 一次性,立即断开 | 保持连接,直到主动断开 |
数据大小 | 建议小数据 | 可用于流式数据 |
适用对象 | content ↔ background,popup ↔ background 等 | content ↔ background 持续通信 |
是否支持多端口 | ❌每次调用独立 | ✅ 多个 port 可共存 |
✅ 建议使用方式(经验)
场景 | 推荐方式 |
---|---|
上传文件 < 5MB,参数少 | sendMessage |
上传大文件、分片、实时回传上传进度 | connect + port.postMessage |
页面只需发送一次请求,比如查询状态 | sendMessage |
插件与页面持续通讯(如 WebSocket 中继) | connect |
网页直接与background.js 直接通讯的方式
在 Chrome 插件中,网页与 background.js
(或 service worker)之间的通信是否必须经过 content.js
,要根据情况区分。下面详细解释各种通信方式:
✅ 结论:
网页想要直接与 background.js
通信,不必须经过 content.js
,但前提是网页主动连接插件。
📌 一、三种通信方式汇总
方式 | 是否需要 content.js 中转 | 说明 |
---|---|---|
1. ✅ 网页 → content.js → background.js | 是 | 最常见,用 postMessage + runtime.sendMessage |
2. ✅ 网页 → background.js (通过 chrome.runtime.connect 或 chrome.runtime.sendMessage ) | 否 | 只限网页主动发起,插件必须有 externally_connectable |
3. ✅ 插件注入脚本 → 网页 → content.js → background.js | 是 | 一种变种,脚本非网页自身控制,而是插件注入 |
🧠 二、网页直接与 background.js
通信的条件
1. 使用 chrome.runtime.sendMessage
或 chrome.runtime.connect
网页可以直接调用如下代码:
// 网页中(非插件脚本)
chrome.runtime.sendMessage(
'扩展ID',
{ greeting: 'hello' },
response => {
console.log('收到来自插件的回应:', response);
}
);
2. 需要插件在 manifest.json
中声明权限:
"externally_connectable": {
"matches": ["https://example.com/*"] // 或 ["<all_urls>"](调试用)
}
否则网页是没有权限连接插件的,调用会失败。
3. 插件 background.js
需要监听来自网页的连接:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
console.log('收到网页的消息:', request);
sendResponse({ received: true });
}
);
❗ 注意事项:
- 插件必须知道自己的 ID(或者网页知道插件的 ID),才能发送消息。
- 多数情况下推荐使用
content.js
中转,这样可以安全地监听网页中的 JS 行为,并与插件通信。
✅ 推荐使用场景总结:
场景 | 是否推荐使用 content.js 中转 |
---|---|
插件控制网页,监听按钮、脚本注入等 | ✅ 是 |
网页是你自己开发的网站,想和插件通信 | ❌ 可省略 content.js ,用 runtime.sendMessage |
插件为通用扩展,不知道网页是否可信 | ✅ 用 content.js 更安全 |