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

Chrome扩展:后台脚本发消息至内容脚本重复接收的修复方案

问题描述

我正在开发一款带可点击链接和按钮的Google Chrome扩展,需求是点击跳转按钮/链接完成页面跳转后,通过后台脚本终止扩展运行。目前遇到的问题是:后台脚本日志显示仅发送了一次消息,但内容脚本的onMessage监听器却接收到两条消息,该如何修复?


后台脚本(background.js)

chrome.webNavigation.onCompleted.addListener((details) => {
  chrome.tabs &&
    chrome.tabs.query({ active: true, currentWindow: true }, () => {
      setTimeout(() => {
        const storage = chrome.storage.local;
        storage.get("activeProcess", (result) => {
          let activeProcess = Object.values(result)[0];
          if (activeProcess && details.frameType === "outermost_frame") {
            const tabId = details.tabId;
            storage.get("message", (result) => {
              result.message.url = details.url;
              result.message.source = "background";
              console.log("message sent");
              chrome.tabs.sendMessage(tabId, result.message, (res) => {
                console.log(res);
              });
            });
          }
        });
      }, 100);
    });
  return true;
});

后台日志输出:message sent

内容脚本(content.js)

chrome.runtime.onMessage.addListener(messagesListener);

async function messagesListener(message, sender, response) {
  await processMessage(message, sender, response);
}

export const processMessage = async (message, sender, response) => {
  console.log("message received")
}

内容脚本日志输出:message received message received


解决方案

问题根源

  1. webNavigation.onCompleted重复触发:部分页面会因重定向、资源二次加载等原因多次触发该事件,即使判断了frameType === "outermost_frame",仍可能出现重复触发的情况。
  2. 冗余异步逻辑:代码中已通过details.tabId拿到目标标签ID,却额外调用chrome.tabs.query,多余的异步回调会增加逻辑混乱的概率。
  3. 无重复处理标记:未对已发送消息的标签做状态标记,导致后续触发的事件再次发送相同消息。

修复步骤

1. 优化后台脚本逻辑,避免重复发送

移除冗余的chrome.tabs.query和setTimeout,添加标签处理状态标记:

// 存储已处理过的标签ID,避免重复发送消息
const processedTabs = new Set();

chrome.webNavigation.onCompleted.addListener((details) => {
  // 过滤非外层框架或已处理的标签
  if (details.frameType !== "outermost_frame" || processedTabs.has(details.tabId)) {
    return;
  }

  const storage = chrome.storage.local;
  storage.get("activeProcess", (result) => {
    let activeProcess = Object.values(result)[0];
    if (activeProcess) {
      const tabId = details.tabId;
      storage.get("message", (result) => {
        result.message.url = details.url;
        result.message.source = "background";
        console.log("message sent");
        chrome.tabs.sendMessage(tabId, result.message, (res) => {
          console.log(res);
          // 标记该标签已处理
          processedTabs.add(tabId);
          // 标签关闭时清除标记,释放内存
          chrome.tabs.onRemoved.addListener((removedTabId) => {
            processedTabs.delete(removedTabId);
          });
        });
      });
    }
  });
}, {
  // 可选:限制监听HTTP/HTTPS页面,减少无效触发
  url: [{ schemes: ["http", "https"] }]
});

2. 内容脚本添加去重逻辑(可选)

如果仍存在重复接收情况,可在内容脚本中根据消息标识去重:

const receivedMessages = new Set();

chrome.runtime.onMessage.addListener(async (message, sender, response) => {
  // 用URL+来源作为消息唯一标识
  const messageKey = `${message.url}-${message.source}`;
  if (receivedMessages.has(messageKey)) {
    return;
  }
  receivedMessages.add(messageKey);
  await processMessage(message, sender, response);
});

export const processMessage = async (message, sender, response) => {
  console.log("message received");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:07:41