"Receiving end does not exist" 将消息传递给注入的内容脚本时

"Receiving end does not exist" when passing message to injected content script

在 Firefox 的附加组件中,我试图将后台脚本中的代码注入选项卡,然后将消息传递给它。不幸的是,内容脚本似乎仅在消息已发送后才添加侦听器,从而导致错误。我错过了什么?这是我的示例代码:

manifest.json:

{
    "description": "Test background to content message passing",
    "manifest_version": 2,
    "name": "Background content message passing",
    "version": "0.1.0",
    "default_locale": "en",

    "applications": {
        "gecko": {
            "id": "bcm@example.com",
            "strict_min_version": "51.0"
        }
    },

    "permissions": [
        "contextMenus",
        "<all_urls>"
    ],

    "background": {
        "scripts": ["background.js"]
    }
}

background.js:

"use strict";

const {contextMenus, i18n, runtime, tabs} = browser;

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(runtime.sendMessage({"result": 42}))
        .then(console.log("Debug: runtime message sent"))
        .catch(console.error.bind(console));
    }
});

contextMenus.create({
    id: "bgd-cnt-msg",
    title: "Test message passing",
    contexts: ["all"],
    documentUrlPatterns: ["<all_urls>"]
});

content.js

"use strict";

console.log("Debug: executing content script");

browser.runtime.onMessage.addListener(function (message) {
    console.log("Debug: received message %O", message);
});

console.log("Debug: added listener");

选择上下文菜单条目的结果是

Debug: runtime message sent                                  background.js:11:15
Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9
Error: Could not establish connection. Receiving end does not exist.   undefined

即,上下文脚本在向选项卡发送消息后执行。如何在发送消息前添加监听器?


根据@Thắng 的建议,我更改了代码以使用 tabs.sendMessage 而不是 runtime.sendMessage:

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(tabs.sendMessage(tab.id, {"result": 42}))
        .then(console.log("Debug: runtime message sent"))
        .catch(console.error.bind(console));
    }
});

现在报错有点早:

Debug: runtime message sent                                  background.js:11:15
Error: Could not establish connection. Receiving end does not exist.   undefined
Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9

感谢@Thắng,他提供了一个有效的解决方案,我修复了我的代码,不仅使用 tabs.sendMessage,而且还传递回调函数:

contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId == "bgd-cnt-msg") {
        tabs.executeScript(tab.id, {
            file: "/content.js",
        })
        .then(function () { tabs.sendMessage(tab.id, {"result": 42}) })
        .then(function () { console.log("Debug: runtime message sent") })
        .catch(console.error.bind(console));
    }
});

content.js

中进行了额外修复
browser.runtime.onMessage.addListener(function (message) {
    console.log("Debug: result is " + message.result);
});

我现在得到

Debug: executing content script                                     content.js:3
Debug: added listener                                               content.js:9
Debug: runtime message sent                                  background.js:11:15
Debug: result is 42                                                 content.js:6

在后台脚本中,您需要让它知道它应该将消息发送到哪个选项卡,所以不要为此使用 runtime.sendMessage

var sending = chrome.tabs.sendMessage(
  tabId,                   // integer
  message,                 // any
  options                  // optional object
)

在这里查看更多内容(对于 webExtensions 但也与 Chrome 兼容):https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/sendMessage

您的完整扩展名在这里(您可能需要将所有 browser.* 更改为 chrome.*): https://drive.google.com/file/d/1KGf8tCM1grhhiC9XcHOjsrbBsIZGff3e/view?usp=sharing