用于后台上下文中一个脚本的消息被所有脚本接收

Messages intended for one script in the background context are received by all

我有一个具有以下结构的 WebExtension:

webextension [directory]
   - background.js
   - page1.html
   - page1.js
   - page2.html
   - page2.js

background.js 侦听错误。如果有的话,它会指示其回调函数使用 HTML 页面更新选项卡,page2.js 包含一个按钮。

HTML 脚本 page2.js 首先向 background.js 发送一条消息,然后background.js 回复 page2.js。这部分工作正常。

然后,正如您在代码中看到的那样,page2.html 包含一个按钮,如果单击,它将执行回调函数中的代码。然后,它将调用 refreshIndexPage,它应该发送一条消息到附加到 page1.htmlpage1.js .

问题:当我在 page2.js[=119= 之间添加消息传递 API 时]refreshIndexPage 中,来自 page2 的消息被发送到 background.js。我不希望这种情况发生。正如我将在输出中显示的那样,我得到:In background.js: received: undefined

问题:

  1. 如何从 page2.js 发送消息到 page1.js 而无需 background.js 也在侦听来自 page2.js 的消息时会感到困惑并收到不适合它的消息吗?如何指定这条消息是从page2.jspage1.js?

这是将消息从 page2.js 添加到 page1.js 后的输出。 控制台输出

inside refreshIndexPage
In background.js: received: undefined
inside handleRefreshResponse
  1. page1.html:
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>
  <h1>Pag1.html</h1>
  <input type="button" id="page1-button" value="click"></input>
  <script src="page1.js"></script>
</body>
</html>
  1. page1.js:
function displayAll() {
  console.log("inside display all");
} //end displayAll

//should listen to messages from pag2.js
browser.runtime.onMessage.addListener(handleRefreshMessage);

function handleRefreshMessage(request, sender, sendResponse) {
  console.log("In page1.js: message received" + request.refreshRequest);
  sendResponse("response from page1.js to page2.js");
}
  1. background.js:
console.log("inside background");

//add a listener for the toolbar icon. If clicked, open page1.html
browser.browserAction.onClicked.addListener((tab) => {
  // disable the active tab
  var creating = browser.tabs.create({"url": "page1.html"});
  creating.then((tab) => {
    browser.browserAction.setIcon({tabId: tab.id, path: "icons/red-64.png"});
  });//end creating.then
});//end addListener

var target = "<all_urls>";
function log(responseDetails) {
  console.log("inside response details");
  errorTab = responseDetails.tabId;
  if(true) {
    console.log("inside if");
    browser.tabs.update(responseDetails.tabId,{url: "page2.html"});

    //this message to wait request from page2.js
    browser.runtime.onMessage.addListener(handleMessage);
  } //end if
}//end log

function handleMessage(request, sender, sendResponse) {
  console.log("In background.js: received: " + request.scriptRequest);
  sendResponse({errorTab: errorTab});
}

var errorListening = browser.webRequest.onErrorOccurred.addListener(log, {
    urls: [target],
    types: ["main_frame"]
});
  1. page2.html:
<html>
<head>
  <meta charset="UTF-8">
</head>
<body>
  <h1>Pag2.html</h1>
  <input type="button" id="page2-button" value="click"></input>
  <script src="page2.js"></script>
</body>
</html>
  1. page2.js:
/*self-calling function conatins sendMessage to background script*/
(function notifyBackgroundPage() {
    var sending = browser.runtime.sendMessage({
    scriptRequest: "From pag2.js. request for data"
  });
  sending.then(handleResponse);
})();

function handleResponse(message) {
  console.log(`In page2.js: data from background is: ${message.errorTab}`);
} //handleResponse

function myFunction() {
  refreshIndexPage();//end .then
}//end myFunction

//refreshIndexPage should send message to page1.js only when the button is clicked.
function refreshIndexPage() {
  console.log("inside refreshIndexPage");
  var sending = browser.runtime.sendMessage({
    refreshRequest: "From page2.js"
  });
  sending.then(handleRefreshResponse);
}//end refreshIndex

function handleRefreshResponse() {
  console.log("inside handleRefreshResponse");
}//end handleRefreshResponse

var page2Button = document.getElementById("page2-button");
page2Button.addEventListener('click', myFunction);

已注册 runtime.sendMessage() are received in all scripts in the background context which have a runtime.onMessage 侦听器发送的消息,发送消息的脚本除外。1 您无法限制此类消息的收件人.

因此,您必须创建一些方法来确定消息是否针对接收它的每个脚本。这可以通过多种方式完成,但所有方式都基于以下任一方式:

  1. 内容messageand/or
  2. sender

这两个都作为参数提供给 runtime.onMessage() 侦听器。

使用message

要使用 message,您必须 选择 以在 message 上强加一些结构。 message 可以是您选择发送的任何 JSON-ifiable 数据。强加一些结构可以让您更轻松地使用更复杂的消息,并更可靠地在脚本之间传递信息。没有什么是预定义的。你可以使用任何你想要的。但是,在您的选择中保持一致通常会使编程更容易,并且几乎总是使代码更易于维护。

就个人而言,我通常会出于不同的原因发送消息。对于每个分机,我通常会选择始终 发送具有特定格式的Object。每个扩展名的格式可能不同,但通常类似于:

var message = {
    type: 'requestFoo',
    //subType: 'Used if the type needs to be further split',
    data: dataNeededForRequest
    //You can add whatever other properties you want here.
};

如果扩展有多个可能的收件人,那么 A) 只有一个收件人会理解如何处理 requestFoo type 消息,而所有其他人都会忽略这样的 message types,或者如果有多个后台上下文脚本可以处理 requestFoo 类型,那么我会添加一个 recipientdestination 属性。因此,message 看起来像:

var message = {
    type: 'requestFoo',
    //subType: 'Used if the type needs to be further split',
    recipient: 'page2.js',
    data: dataNeededForRequest
    //You can add whatever other properties you want here.
};

当每个脚本收到 message 时,他们将检查 recipient 是否与收到消息的脚本匹配,以及代码是否理解如何处理 type message.

请记住,上面的结构正是我碰巧使用的。您可以定义任何您想要的结构,也能满足您的需求。

使用sender

如果脚本从不对从特定发件人收到的邮件执行操作,或者如果脚本执行在来自特定发件人的邮件上,然后该脚本可以检查 sender runtime.MessageSender Object to see if the parameters match ones from a sender for which it is to act on the message. If you use this methodology, you will most commonly be checking the sender.url.

仅根据 sendermessage 采取行动的选择比基于 message 的内容要受限得多。但是,除了 message 中提供的信息外,它还非常有用。它还提供了一种方法来了解不能被欺骗的消息的发件人。此外,这意味着您不需要传达关于哪个范围是消息发件人的信息,当然,除非您在范围内有多个可能的发件人(即在 URL/page 中) .


1. 51 之前的版本中的 bug in Firefox 会导致在发送消息的脚本中接收到消息。如果您希望您的扩展在该版本或更早版本中使用,您 必须 考虑到这种可能性(即忽略它们),因为某些情况可能会导致 Firefox 锁定(例如,如果您总是发送收到消息时会收到一条新消息)。