在后台上下文中用于一个脚本的消息被全部接收 [英] Messages intended for one script in the background context are received by all

查看:120
本文介绍了在后台上下文中用于一个脚本的消息被全部接收的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  webextension [目录] 
- background.js
- page1.html
- page1.js
- page2.html
- page2.js



background.js 监听错误。如果有的话,它会指示它的回调函数用一个包含按钮的HTML页面 page2.js 来更新标签。



HTML脚本 page2.js 首先向 background.js 发送消息, background.js 回复 page2.js 。这部分工作正常。
$ b 然后,如代码中所见, page2.html 包含一个按钮,如果点击,它将执行代码回调函数。然后,它会调用 refreshIndexPage 这个消息给 page1.html 附加的 page1.js



问题:当我在 page2.js page1.js refreshIndexPage 中,来自page2的消息被发送到 background.js 。我不想要这样的事情发生。正如我将在输出中显示,我得到:在background.js:received:undefined



问题: / p>


  1. 如何将 page2.js 发送到 page1.js 使 background.js 也听从 page2.js 的消息会感到困惑,并收到不适合它的消息?如何将这条信息从 page2.js 指定为 page1.js

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

 里面refreshIndexPage 
在background.js中:received: undefined
内部handleRefreshResponse




  1. page1.html



< html>
< head>
< meta charset =UTF-8>
< / head>
< body>
< h1> Pag1.html< / h1>
< input type =buttonid =page1-buttonvalue =click>< / input>
< script src =page1.js>< / script>
< / body>
< / html>




  1. page1.js


$ b

  function displayAll(){
console.log(inside display all);
} // end displayAll

//应该监听来自pag2.js的消息
browser.runtime.onMessage.addListener(handleRefreshMessage);

函数handleRefreshMessage(request,sender,sendResponse){
console.log(In page1.js:message received+ request.refreshRequest);
sendResponse(从page1.js到page2.js的响应);




  1. background .js


$ b

  console.log 内部背景); 

//为工具栏图标添加一个侦听器。如果点击,打开page1.html
browser.browserAction.onClicked.addListener((tab)=> {
//禁用活动标签
var creating = browser.tabs.create({ (url):page1.html});
creating.then((tab)=> {
browser.browserAction.setIcon({tabId:tab.id,path:icons / red -64.png});
}); // end created.then
}); // end addListener

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

//这个消息等待来自page2.js的请求
browser.runtime.onMessage.addListener(handleMessage);
} // end if
} // end log

函数handleMessage(request,sender,sendResponse){
console.log(in background.js:收到:+ 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 =buttonid =page2-buttonvalue =click>< / input>
< script src =page2.js>< / script>
< / body>
< / html>




  1. page2.js


$ b

  / *自调用函数conatins sendMessage后台脚本* / 
(函数notifyBackgroundPage(){
var sending = browser.runtime.sendMessage({
scriptRequest:from pag2.js. request for data
}) ;
sending.then(handleResponse);
})();

函数handleResponse(消息){
console.log(`在page2.js:来自后台的数据是:$ {message.errorTab}`);
} // handleResponse

函数myFunction(){
refreshIndexPage(); //结束.then
} //结束myFunction

// refreshIndexPage只有当按钮被点击时才会发送消息给page1.js。
函数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
$ b $ var page2Button = document.getElementById(page2-button);
page2Button.addEventListener('click',myFunction);


解决方案

runtime.sendMessage() 在后台上下文中的所有脚本中都有收到 runtime.onMessage 监听器已注册,但是发送消息的脚本除外。 1 您无法限制这些信息的收件人。



因此,您必须创建一些方法来确定邮件是否适用于接收的每个脚本它。这可以通过各种方式来完成,但是它们都是基于以下任一方式: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessage#Parameters =nofollow noreferrer> message 和/或

  • sender

  • 这两个都作为参数提供给 runtime.onMessage()监听器。使用 message

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

    就个人而言,我通常会以不同的原因发送消息。对于每个扩展,我通常会选择总是发送一个具有特定格式的对象。这种格式对于每个扩展名可能都不相同,但是通常看起来像这样:
    $ b

    var message = {
    类型:'requestFoo',
    // subType:'如果类型需要进一步拆分,使用
    data:dataNeededForRequest
    //你可以添加任何其他属性你想在这里。
    };

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

    var message = {
    type:'requestFoo',
    // subType:'如果需要进一步拆分类型,使用
    recipient:'page2.js',
    data:dataNeededForRequest
    //你可以在这里添加你想要的任何其他属性。
    };

    当每个脚本收到消息时,请检查收件人是否与接收到该邮件的脚本相匹配,以及代码是否理解如何处理类型 message



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

    使用发件人



    如果一个脚本从不 对从特定发件人收到的邮件采取行动,或者只对 那么该脚本可以检查发件人 runtime.MessageSender 查看参数是否与来自发件人的参数匹配消息。如果你使用这种方法,你通常会检查 sender.url



    基于对<$ c $仅仅基于发送者的消息明显比基于消息的内容有限。但是,除了在消息中提供的信息之外,它还是非常有用的。它还提供了一种方法来知道邮件的发件人不能被欺骗。另外,这意味着你不需要传递关于哪个范围是消息发送者的信息,除非你在范围内有多个可能的发送者(即在URL /页面中)。 / p>




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


    I have a WebExtension with the following structure:

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

    The background.js listens for errors. If any, it instructs its callback function to update the tab with an HTML page, page2.js that contains a button.

    The HTML script page2.js starts by sending a message to the background.js and background.js replies to page2.js. This part works fine.

    Then, as you see in the code, page2.html contains a button if clicked, it will execute code in the callback function. Then, it will call refreshIndexPage which should send a message to page1.js which is attached to page1.html.

    The Problem: When I added the messaging APIs between page2.js and page1.js in the refreshIndexPage, the message from page2 gets sent to the background.js. I do not want this to happen. As I will show in the output, I get: In background.js: received: undefined

    Questions:

    1. How can you send a message from page2.js to page1.js without making background.js that also listens for a message from page2.js gets confused and receives the message that is not meant for it? How to specify that this message it is from page2.js to page1.js?

    Here is the output after adding messages from page2.js to page1.js. Console output

    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);
    

    解决方案

    Messages sent by runtime.sendMessage() are received in all scripts in the background context which have a runtime.onMessage listener registered, except the script from which the message was sent.1 There is no way for you to restrict the recipients of such messages.

    Thus, you have to create some methodology to determine if the message is intended for each script which receives it. This can be done in a wide variety of ways, but all of them are based on either:

    1. The contents of the message and/or
    2. The sender

    Both of these are provided as arguments to the runtime.onMessage() listener.

    Using message

    To use the message you have to choose to impose some structure on the message. The message can be any JSON-ifiable data you choose to send. Imposing some structure allows you to more easily use messages more complex and more reliably communicate information between your scripts. There is nothing that is predefined. You can use whatever you desire. However, being consistent in your choices usually makes it easier to program and almost always makes code easier to maintain.

    Personally, I'm usually sending messages for different reasons. For each extension, I'll usually choose to always send an Object with a particular format. That format may be different for each extension, but it usually looks something like:

    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.
    };
    

    If the extension has multiple possible recipients, then either A) only one recipient would understand how to handle a requestFoo type message, and all others would ignore such message types, or if there were multiple background context scripts which could handle requestFoo types, then I would add a recipient or destination property. Thus, the message would look like:

    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.
    };
    

    When each script received the message they would check both that the recipient matched the script which had received the message and that the code understood how to handle the type of message.

    Keep in mind that the structure above is just what I happen to use. You can define whatever structure you desire which also fulfills your needs.

    Using sender

    If a script is never to act on messages received from a specific sender(s), or if it is to only act on messages from specific senders, then that script can check the 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.

    Basing a choice to act on a message based solely on the sender is significantly more limited than being based on the contents of the message. However, it can be quite useful when used in addition to information provided in the message. It also provides a way to know the sender of the message which can not be spoofed. In addition, it means that you don't need to communicate information as to which scope was the sender of the message, unless, of course, you have more than one possible sender in the scope (i.e. in the URL/page).


    1. A bug in Firefox in versions prior to 51 results in messages being received in the script which sent them. If you expect your extension to be used in that version or earlier you must account for that possibility (i.e. ignore them), as some situations can result in locking up Firefox (e.g. if you always send a new message when you receive a message).

    这篇关于在后台上下文中用于一个脚本的消息被全部接收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆