You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展内容脚本重复注入及消息通信异常求助

Chrome扩展重复注入Content Script及关闭停止问题解决

问题拆解

你遇到三个核心问题:

  1. 扩展加载/刷新时,现有标签页重复注入Content Script,导致DOM操作重复执行;
  2. 用sendMessage判断是否已注入时,控制台一直报Could not establish connection错误;
  3. 扩展关闭(禁用/卸载)时,Content Script未停止工作。

解决步骤

1. 修复Service Worker的事件监听

Manifest V3中,Service Worker不能用self.oninstall,必须用chrome.runtime.onInstalled,同时区分安装、更新、Chrome启动场景:

// background.js
chrome.runtime.onInstalled.addListener(async (details) => {
  // 仅在安装或扩展更新时处理现有标签
  if (details.reason === 'install' || details.reason === 'update') {
    const tabs = await chrome.tabs.query({url: "<all_urls>"});
    for (const tab of tabs) {
      await injectIfNotExists(tab.id);
    }
  }
});

// 扩展刷新(重新加载)时,Service Worker重启,补充处理现有标签
chrome.runtime.onStartup.addListener(async () => {
  const tabs = await chrome.tabs.query({url: "<all_urls>"});
  for (const tab of tabs) {
    await injectIfNotExists(tab.id);
  }
});

2. 安全判断是否需要注入(避免重复)

放弃用sendMessage判断(容易报错),改为执行一段小脚本检查标记:

// background.js 新增工具函数
async function injectIfNotExists(tabId) {
  try {
    // 检查当前标签是否已注入(用全局变量标记)
    const checkResult = await chrome.scripting.executeScript({
      target: {tabId: tabId},
      func: () => window._textHighlighterInjected === true,
      world: 'ISOLATED' // 和Content Script同一隔离环境
    });

    if (!checkResult[0].result) {
      // 并行注入JS和CSS,提升效率
      await Promise.all([
        chrome.scripting.executeScript({
          target: {tabId: tabId},
          files: ['content.js']
        }),
        chrome.scripting.insertCSS({
          target: {tabId: tabId},
          files: ['styles.css']
        })
      ]);
    }
  } catch (error) {
    // 跳过无法注入的标签(如chrome://页面、about:blank)
    console.log('跳过标签:', tabId, error.message);
  }
}

然后在Content Script里添加标记:

// content.js
// 标记已注入,防止重复
window._textHighlighterInjected = true;

3. 解决sendMessage报错问题

如果一定要用消息通信,必须捕获chrome.runtime.lastError,避免控制台炸锅:

chrome.tabs.sendMessage(tabId, 'check-injected', (response) => {
  if (chrome.runtime.lastError) {
    // 通信失败,说明未注入
    injectIfNotExists(tabId);
    return;
  }
  if (!response) injectIfNotExists(tabId);
});

4. 扩展关闭时立即停止工作

在Content Script里监听chrome.runtime.onDisconnect事件,触发时清理所有资源:

// content.js
// 监听扩展断开(禁用/卸载)
chrome.runtime.onDisconnect.addListener(() => {
  cleanup();
});

// 清理函数,根据你的业务逻辑调整
function cleanup() {
  // 移除高亮元素
  document.querySelectorAll('.highlight').forEach(el => el.remove());
  // 移除事件监听
  // document.removeEventListener('mouseup', yourHighlightFunc);
  // 清除定时器
  // clearInterval(yourTimer);
  console.log('扩展已关闭,资源已清理');
}

完整代码

Manifest.json(无需修改)

{
    "name": "Text highlighter",
    "description": "Text highlighter",
    "version": "1.0.0",
    "manifest_version": 3,
    "background": {
      "service_worker": "background.js"
    },
    "options_ui": {
      "page": "options.html",
      "open_in_tab": false
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["content.js"],
        "css": [ "styles.css" ]
      }
    ],
    "permissions": ["storage", "activeTab", "scripting", "tabs"],
    "host_permissions": ["<all_urls>"]
}

background.js

chrome.runtime.onInstalled.addListener(async (details) => {
  if (details.reason === 'install' || details.reason === 'update') {
    const tabs = await chrome.tabs.query({url: "<all_urls>"});
    for (const tab of tabs) {
      await injectIfNotExists(tab.id);
    }
  }
});

chrome.runtime.onStartup.addListener(async () => {
  const tabs = await chrome.tabs.query({url: "<all_urls>"});
  for (const tab of tabs) {
    await injectIfNotExists(tab.id);
  }
});

async function injectIfNotExists(tabId) {
  try {
    const checkResult = await chrome.scripting.executeScript({
      target: {tabId: tabId},
      func: () => window._textHighlighterInjected === true,
      world: 'ISOLATED'
    });

    if (!checkResult[0].result) {
      await Promise.all([
        chrome.scripting.executeScript({
          target: {tabId: tabId},
          files: ['content.js']
        }),
        chrome.scripting.insertCSS({
          target: {tabId: tabId},
          files: ['styles.css']
        })
      ]);
    }
  } catch (error) {
    console.log('跳过无法注入的标签:', tabId, error.message);
  }
}

content.js

window._textHighlighterInjected = true;

chrome.runtime.onDisconnect.addListener(() => {
  cleanup();
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  console.log('收到消息:', request);
  sendResponse(true);
  return true;
});

function cleanup() {
  document.querySelectorAll('.highlight').forEach(el => el.remove());
  // 这里添加你的其他清理逻辑
  console.log('扩展已停止,资源已清理');
}

内容的提问来源于stack exchange,提问作者webdigga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:05:58