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

Chrome扩展使用executeScript注入脚本时出现document未定义错误

Chrome扩展注入脚本报错:ReferenceError: document is not defined

问题场景

开发需验证用户付费状态的Chrome扩展,后台脚本通过ExtensionPay API完成验证后,调用chrome.scripting.executeScript向标签页注入脚本,触发以下错误:

Error handling response: ReferenceError: document is not defined

相关代码

background.js

importScripts("ExtPay.js", "script.js", "monitorNetflix.js");
const extpay = ExtPay("censor-bad-words-on-netflix")
extpay.startBackground();

const millisecondsInOneDay = 86400000;

const authenticateUser = () => {
  chrome.storage.sync.set({authenticated: true});
  chrome.tabs.query({}, function(tabs) {
    for (var i = 0; i < tabs.length; i++) {
      var tabId = tabs[i].id;
      chrome.scripting.executeScript({ 
        target: {tabId: tabId},
        func: script 
      }, _=>{
        let e = chrome.runtime.lastError;
        if(e !== undefined){
          console.log(tabId, _, e);
        }
      });
      chrome.scripting.executeScript({ 
        target: {tabId: tabId},
        func: monitorNetflix 
      }, _=>{
        let e = chrome.runtime.lastError;
        if(e !== undefined){
          console.log(tabId, _, e);
        }
      });
    }
  });
};

extpay.getUser().then(user => {
  if (user.paid) {
    console.log("用户付费时间: ", user.paidAt)
    console.log("已启用功能");
    authenticateUser();
  } else {
    if (!user.trialStartedAt) {
      console.log("启动3天试用");
      extpay.openTrialPage("3-day");
    }
    else if (new Date().getTime() - user.trialStartedAt.getTime() > millisecondsInOneDay * 0.01) {
      console.log("试用已过期");
      extpay.openPaymentPage().catch((rej) => {
        console.log(rej, "网络出错");
      });
    } else {
      console.log("试用进行中");
    }
  }
}).catch((rej) => {
  console.log(rej, "网络出错");
}); 

extpay.onPaid.addListener(user => {
  console.log("用户完成付费");
  authenticateUser();
});

extpay.onTrialStarted.addListener(user => {
  console.log("用户启动试用");
  authenticateUser();
});

manifest.json

{
  "manifest_version": 3,
  "name": "AppName",
  "description": "",
  "version": "0.1.0",
  "permissions": [
    "storage",
    "scripting",
    "tabs"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "host_permissions": ["https://*/*"],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["script.js"]
    },
    {
      "matches": ["https://www.netflix.com/*"],
      "js": ["script.js", "monitorNetflix.js"]
    },
    {
      "matches": ["https://extensionpay.com/*"],
      "js": ["ExtPay.js"],
      "run_at": "document_start"
    }
  ], 
  "action": {
    "default_icon": "icon.png"
  },
  "icons": {
    "128": "icon.png"
  }
}

script.js

chrome.storage.sync.get(["authenticated"], function(result) {
  console.log('当前认证状态: ' + result.authenticated);
  if (result.authenticated) {
    monitorNetflix();
  }
});

const monitorNetflix = (function () {
  // 依赖document的逻辑...
}

错误原因

  1. 后台Service Worker无DOM环境:background.js通过importScripts导入了script.js和monitorNetflix.js,而后者包含依赖document的代码。Service Worker运行在无浏览器DOM的环境中,加载时直接触发document未定义的错误。
  2. 注入函数方式错误:chrome.scripting.executeScript的func参数要求传入可序列化的独立函数,但你传入的script并不是一个定义好的函数(script.js是直接执行的逻辑),且后台环境中的monitorNetflix变量无法在页面上下文正常运行。
  3. 重复注入冲突:manifest.json已配置内容脚本自动注入,后台手动注入会导致逻辑重复,引发上下文混乱。

修复方案

1. 移除后台对DOM脚本的导入

修改background.js,仅保留适配后台环境的ExtensionPay脚本:

importScripts("ExtPay.js");
const extpay = ExtPay("censor-bad-words-on-netflix")
extpay.startBackground();

const millisecondsInOneDay = 86400000;

const authenticateUser = () => {
  chrome.storage.sync.set({authenticated: true});
  // 无需手动注入,由内容脚本读取storage状态执行逻辑
};

// 后续extpay相关逻辑保持不变

2. 调整内容脚本逻辑

修改script.js,通过监听storage状态触发逻辑,避免重复执行:

// 监听认证状态变化
chrome.storage.sync.onChanged.addListener((changes, areaName) => {
  if (areaName === 'sync' && changes.authenticated?.newValue) {
    runMonitor();
  }
});

// 初始化检查状态
chrome.storage.sync.get(["authenticated"], function(result) {
  console.log('当前认证状态: ' + result.authenticated);
  if (result.authenticated) {
    runMonitor();
  }
});

// 封装执行逻辑,避免重复
function runMonitor() {
  if (window._monitorRan) return;
  window._monitorRan = true;
  monitorNetflix();
}

3. 修正内容脚本配置

确保manifest.json中内容脚本在DOM就绪后执行:

{
  // ...其他配置不变
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["script.js"],
      "run_at": "document_idle"
    },
    {
      "matches": ["https://www.netflix.com/*"],
      "js": ["script.js", "monitorNetflix.js"],
      "run_at": "document_idle"
    },
    {
      "matches": ["https://extensionpay.com/*"],
      "js": ["ExtPay.js"],
      "run_at": "document_start"
    }
  ]
}

4. 规范monitorNetflix.js定义

确保函数在页面上下文可正常执行:

const monitorNetflix = function() {
  // 这里编写依赖document的DOM操作逻辑
  console.log("执行Netflix监控", document);
};

关键提示

  • Service Worker(后台脚本)永远不能访问document、window等浏览器DOM对象,所有页面相关逻辑必须放在内容脚本或注入的页面脚本中。
  • 若需手动注入脚本,优先使用chrome.scripting.executeScript的files参数传入脚本文件,而非func参数传递后台函数。
  • 尽量通过chrome.storage传递状态,让内容脚本自行判断执行时机,这是Chrome扩展的标准架构模式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:10:28