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

Chrome扩展:背景脚本无法向内容脚本发送executeAction消息

问题诊断与修复方案

核心问题分析

你的代码存在几个关键错误,导致消息无法正常发送:

  1. actionCompleted 回调中 tabId 未定义
    当内容脚本发送 actionCompleted 消息时,代码尝试调用 triggerAction(tabId),但此处的 tabId 从未被声明或赋值,会抛出 ReferenceError,直接终止后续执行。

  2. triggerAction 函数参数不匹配
    在 chrome.tabs.onUpdated 的回调中,你调用 triggerAction(tabId),但 triggerAction 函数定义时接收的是完整 tab 对象(而非数字类型的 tabId)。这会导致函数内部访问 newTab.id 时得到 undefined,进而使脚本注入和消息发送因无效 tabId 失败。

  3. 缺少 API 错误检查
    Chrome 扩展 API 的回调中未检查 chrome.runtime.lastError,无法及时发现脚本注入或消息发送失败的具体原因。

修复后的代码

background.js

console.log('Background script running');
let actionStep = 0;
let currentTabId = null; // 存储当前操作的 tabId

chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    if (message.action === 'actionCompleted') {
        actionStep++;
        if (currentTabId !== null) {
            triggerAction(currentTabId);
            console.log('Action completed');
        }
    }
    else if (message.action === 'triggerAction') {
        chrome.tabs.create({ url: 'https://www.amazon.com' }, (newTab) => {
            console.log('New tab created:', newTab);
            currentTabId = newTab.id; // 记录当前 tabId
            chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) {
                if (tabId === newTab.id && changeInfo.status === 'complete') {
                    chrome.tabs.onUpdated.removeListener(listener);
                    console.log('ABOUT TO EXECUTE SCRIPT');
                    chrome.scripting.executeScript({
                        target: { tabId: newTab.id },
                        files: ['content.js']
                    }, () => {
                        if (chrome.runtime.lastError) {
                            console.error('Script injection failed:', chrome.runtime.lastError);
                            return;
                        }
                        console.log('Content script injected');
                        triggerAction(newTab.id); // 传入 tabId 而非 tab 对象
                    });
                }
            });
        });
    }
});

chrome.runtime.onInstalled.addListener(() => {
    console.log('Extension installed or updated');
});

// 修改 triggerAction 为接收 tabId 参数
function triggerAction(tabId) {
    console.log('Triggering action number: ', actionStep);
    // 无需重复注入内容脚本,已在 tab 加载完成时注入过
    chrome.tabs.sendMessage(tabId, { action: 'executeAction', actionStep: actionStep }, (response) => {
        if (chrome.runtime.lastError) {
            console.error('Message sending failed:', chrome.runtime.lastError);
            return;
        }
        console.log('Message sent to content script');
    });
}

content.js

console.log('Content script loaded');

async function waitForSelector(selector) {
    console.log(`Waiting for selector: ${selector}`);
    while (document.querySelector(selector) === null) {
        await new Promise(resolve => setTimeout(resolve, 100));
    }
}

async function performAction(action) {
    console.log('Performing action:', action);
    try {
        console.log(`Attempting to perform action: ${action.type} on selector: ${action.selector}`);
        switch (action.type) {
            case 'type':
                await waitForSelector(action.selector);
                const inputElement = document.querySelector(action.selector);
                inputElement.value = action.value;
                inputElement.dispatchEvent(new Event('input', { bubbles: true }));
                inputElement.dispatchEvent(new Event('change', { bubbles: true }));
                console.log('Type action performed.');
                break;
            case 'click':
                await waitForSelector(action.selector);
                document.querySelector(action.selector).click();
                console.log('Click action performed.');
                break;
            case 'scroll':
                await waitForSelector(action.selector);
                document.querySelector(action.selector).scrollIntoView();
                console.log('Scroll action performed.');
                break;
            case 'delay':
                await new Promise(resolve => setTimeout(resolve, action.value));
                console.log(`Delay for ${action.value}ms`);
                break;
            default:
                console.error(`Unsupported action type: ${action.type}`);
                break;
        }
    } catch (error) {
        console.error('Error performing action:', error);
    }
}

const actions = [
    { type: 'type', selector: 'input#twotabsearchtextbox', value: 'The Pragmatic Programmer' },
    { type: 'click', selector: 'input.nav-input[type=submit]' },
    { type: 'delay', value: 5000 },
    { type: 'click', selector: 'a.a-link-normal.s-underline-text.s-underline-link-text.s-link-style.a-text-normal' }
];

async function executeAction(actionStep) {
    console.log('Executing action:', actionStep);
    if (actionStep >= actions.length) {
        console.log('All actions completed');
        return;
    }
    await performAction(actions[actionStep]); // 等待动作完成再发送消息
    chrome.runtime.sendMessage({ action: 'actionCompleted' });
    console.log('Action step completed, waiting for next');
}

chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
    console.log('Received message');
    if (message.action === 'executeAction') {
        console.log('Received message to execute action: ', message.actionStep);
        executeAction(message.actionStep);
    }
});

额外优化点

  • 移除重复的内容脚本注入,避免不必要的资源消耗
  • 在 executeAction 中添加动作边界检查,防止索引越界
  • 等待 performAction 完成后再发送 actionCompleted 消息,确保动作执行顺序正确
  • 增加 API 调用的错误检查,便于调试问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:12:04