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

Chrome扩展注入JS报错:无法读取undefined的'sendMessage'属性

问题:DOM注入脚本无法向Service Worker发送消息

在DOM中注入脚本后,尝试调用chrome.runtime.sendMessage向后台Service Worker发消息时直接报错,相关代码如下:

background.js(后台脚本)

chrome.runtime.onMessage.addListener((req, sender, sendRes) => {
  console.log('this has worked', req, sender, sendRes('this worked'));
  return true;
});

inject.js(用于注入injected.js的内容脚本)

const s = document.createElement('script');
s.src = chrome.runtime.getURL('injected.js');
s.onload = function () {
  this.remove();
};
(document.head || document.documentElement).appendChild(s);

injected.js(注入到页面的脚本)

console.log('fetch interceptor started');
const { fetch: origFetch } = window;
// 此处直接调用时立即报错
chrome.runtime.sendMessage({ works: 'This worked at least' }, (res) => console.log(res));
window.fetch = async (...args) => {
  const response = await origFetch(...args);

  const url = new URL(args[0].url);
  response
    .clone()
    .json()
    .then(async (body) => await sendMessageToBackground({ pathname, body }))
    .catch((err) => console.error(err));

  return response;
};

async function sendMessageToBackground(msg) {
  const res = await chrome.runtime.sendMessage(msg);
  console.log('result message', res);
  console.log('msg', msg);
}

manifest.json相关配置

{
  ...
  "permissions": ["storage", "activeTab", "scripting", "webRequest"],
  "host_permissions": ["https://REDACTED.com/*"],
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["https://REDACTED.com/*"],
      "run_at": "document_start",
      "js": ["inject.js"]
    }
  ],
  "web_accessible_resources": [{ "resources": ["injected.js"], "matches": ["https://REDACTED.com/*"] }],
  ...
}

原因分析

注入到页面DOM的脚本属于页面上下文,和扩展的内容脚本、后台脚本处于不同的执行环境。页面上下文没有权限直接调用Chrome扩展的API(比如chrome.runtime.sendMessage),只有扩展自身的内容脚本、背景脚本等才能访问这些API,所以直接调用会报错。


解决方案

通过内容脚本作为中间代理,建立页面上下文和扩展后台的通信:页面脚本发送自定义事件给内容脚本,内容脚本调用扩展API和后台通信,再把结果返回给页面脚本。

修改后的inject.js(内容脚本)

// 注入页面脚本
const s = document.createElement('script');
s.src = chrome.runtime.getURL('injected.js');
s.onload = function () {
  this.remove();
};
(document.head || document.documentElement).appendChild(s);

// 监听页面脚本发来的自定义事件
window.addEventListener('send-to-background', async (e) => {
  const { message } = e.detail;
  // 调用扩展API发送消息给后台
  const response = await chrome.runtime.sendMessage(message);
  // 把结果发回页面脚本
  window.dispatchEvent(new CustomEvent('background-response', {
    detail: { response }
  }));
});

修改后的injected.js(页面注入脚本)

console.log('fetch interceptor started');
const { fetch: origFetch } = window;

// 替换原有的直接调用,改为通过自定义事件通信
sendMessageToBackground({ works: 'This worked at least' })
  .then(res => console.log(res));

window.fetch = async (...args) => {
  const response = await origFetch(...args);

  const url = new URL(args[0].url);
  response
    .clone()
    .json()
    .then(async (body) => await sendMessageToBackground({ pathname: url.pathname, body }))
    .catch((err) => console.error(err));

  return response;
};

// 封装消息发送函数,通过自定义事件和内容脚本通信
async function sendMessageToBackground(msg) {
  return new Promise((resolve) => {
    // 监听后台返回的结果
    const handleResponse = (e) => {
      window.removeEventListener('background-response', handleResponse);
      resolve(e.detail.response);
    };
    window.addEventListener('background-response', handleResponse);
    
    // 发送自定义事件给内容脚本
    window.dispatchEvent(new CustomEvent('send-to-background', {
      detail: { message: msg }
    }));
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:40:27