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

时间:2017-06-28 13:32:50

标签: javascript firefox firefox-addon firefox-webextensions

我有一个具有以下结构的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.js 发送消息,该消息附加到 page1.html

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

问题:

  1. 如何从 page2.js page1.js 发送消息,而不会使 background.js 同时侦听来自的消息 page2.js 会混淆并收到不适合它的消息?如何指定此消息来自 page2.js page1.js
  2. 以下是将 page2.js 的消息添加到 page1.js 后的输出。 控制台输出

    inside refreshIndexPage
    In background.js: received: undefined
    inside handleRefreshResponse
    
    1. page1.html
    2. <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
      2. 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
        2. 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
          2. <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
            2. /*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);
              

1 个答案:

答案 0 :(得分:1)

runtime.sendMessage()发送的消息在后台上下文中的所有脚本中都被接收,其中注册了runtime.onMessage个侦听器,但发送消息的脚本除外。 1 那里您无权限制此类邮件的收件人。

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

  1. message和/或
  2. 的内容
  3. sender
  4. 这两个都作为runtime.onMessage()监听器的参数提供。

    使用message

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

    就个人而言,我通常会出于不同的原因发送消息。对于每个扩展程序,我们通常会选择始终发送具有特定格式的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 {{1或者,如果有多个后台上下文脚本可以处理types类型,那么我会添加requestFoorecipient属性。因此,destination看起来像:

    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 runtime.MessageSender对象,以查看参数是否与发件人的参数匹配sender。如果您使用此方法,则最常检查sender.url

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

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