【问题标题】:Use asynchronous calls in a blocking webRequest handler在阻塞的 webRequest 处理程序中使用异步调用
【发布时间】:2017-06-16 11:55:55
【问题描述】:

总结

我正在使用browser.webRequest.onBeforeRequest 处理程序。我需要阻止 webRequest,直到我从处理程序中对异步方法的调用中获得信息。我该怎么做?

详情

首先,我为这个冗长的问题道歉。但我希望有人能提供帮助。

我有一个包含 browser.webRequest.onBeforeRequest 的嵌入式扩展(我现在需要使用嵌入式扩展来处理一些 SDK 遗留代码)。

browser.webRequest.onBeforeRequest 回调函数连接到 SDK 扩展并指示它执行某些功能。 SDK 在任务完成后向 webextension 发送回复。我在browser.runtime.sendMessage 中使用了await,以确保在收到SDK 的回复之前停止执行。要使用await,我不得不使用async(但实际上我不想要async功能)。当我不使用await 时,我只会在循环完成所有迭代后从 SDK 获得回复,而不是每次迭代。

下面的示例代码包含许多用于调试的控制台消息,只是为了监视执行。

问题是:我没有得到可靠的结果。在某些情况下(并非全部),http 请求在 SDK 代码生效之前就已发出。我可以确定这一点,因为请求属性必须受到 SDK 代码的影响。控制台按预期显示执行顺序。但是,http 请求不受 SDK 影响(在某些情况下)。

在这个简单的例子中,SDK 只是向 webextension 发送消息,但假设它执行一些功能、读/写操作等。所有的 SDK 任务必须在请求发出之前完成。

我真正需要的是保证在执行所有 SDK 代码之前,Web 请求不会发出。

参考 MDN 文档,它说 browser.webRequest.onBeforeRequest 是一个async 函数。我想知道这是否是问题的根源?如果是这样,如何强制它同步?

embedding-extension [directory]
    - index.js
    - package.json
    - webextension [directory]
       - main.js
       - manifest.json

1)package.json:

{
  "title": "testhybrid",
  "name": "testhybrid",
  "version": "0.0.1",
  "description": "A basic add-on",
  "main": "index.js",
  "author": "",
  "engines": {
    "firefox": ">=38.0a1",
    "fennec": ">=38.0a1"
  },
  "license": "MIT",
  "hasEmbeddedWebExtension": true,
  "keywords": [
    "jetpack"
  ]
}

2)index.js:

const webExtension = require("sdk/webextension");
console.log("in SDK: inside embedding extension");

// Start the embedded webextension
  webExtension.startup().then(api => {
    const {browser} = api;
    browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
      if (msg == "send-to-sdk") {
         console.log("in SDK: message from webExt has been received");
        sendReply({
          content: "reply from SDK"
        }); //end send reply
      }//end if

    }); //end browser.runtime.onMessage

  }); //end webExtension.startup

3)manifest.json:

{
  "manifest_version": 2,
  "name": "webExt",
  "version": "1.0",
  "description": "No description.",
  "background": {
    "scripts": ["main.js"]
  },

  "permissions": [
    "activeTab",
    "webRequest",
  "<all_urls>"
],

"browser_action": {
  "default_icon": {
    "64": "icons/black-64.png"
  },
  "default_title": "webExt"
}
}

4)main.js:

var flag=true;
async function aMethod() {
  console.log("in webExt: inside aMethod");
  for(var x=0; x<2; x++)
  {
    console.log("loop iteration: "+x);
    if(flag==true)
      {
        console.log("inside if");
        console.log("will send message to SDK");
        const reply = await browser.runtime.sendMessage("send-to-sdk").then(reply => {
        if(reply)
        {
          console.log("in webExt: " + reply.content);
        }
        else {
           console.log("<<no response message>>");
        }
        });
      }//end if flag

    else
      {
        console.log("inside else");
      }//end else
  }//end for
}

browser.webRequest.onBeforeRequest.addListener(
  aMethod,
  {urls: ["<all_urls>"],
   types: ["main_frame"]}
);

【问题讨论】:

    标签: javascript firefox firefox-addon firefox-addon-webextensions


    【解决方案1】:

    webRequest.onBeforeRequest documenation 状态(强调我的):

    要取消或重定向请求,首先在extraInfoSpec 数组参数中包含"blocking"addListener()。然后,在监听函数中,返回一个BlockingResponse 对象,设置相应的属性:

    • 要取消请求,请包含一个值为 true 的属性 cancel
    • 要重定向请求,请包含属性redirectUrl,其值设置为您要重定向到的 URL。

    从 Firefox 52 开始,侦听器可以返回 Promise,而不是返回 BlockingResponse,该 BlockingResponse 已被解析。这使侦听器能够异步处理请求。

    您似乎没有执行上述任何操作。因此,事件是完全异步处理的,不可能延迟请求,直到您的处理程序返回。换句话说,正如目前所写的那样,您的webRequest.onBeforeRequest 对 webRequest 绝对没有影响。刚刚通知您的处理程序 webRequest 正在进行中。

    为了完成你想要的,延迟请求直到你执行一些异步操作之后,你需要:

    1. "webRequestBlocking" 添加到您的manifest.json 权限:

        "permissions": [
          "activeTab",
          "webRequest",
          "webRequestBlocking",
          "<all_urls>"
        ],
      
    2. extraInfoSpec 数组参数中的"blocking" 传递给addListener()

      browser.webRequest.onBeforeRequest.addListener(
        aMethod,
        {urls: ["<all_urls>"],
         types: ["main_frame"]},
        ["blocking"]
      );
      
    3. 从您的处理程序返回一个 Promise,它使用 BlockingResponse 解析:

      function aMethod() {
          //Exactly how this is coded will depend on exactly what you are doing.
          var promises = [];
          console.log("in webExt: inside aMethod");
          for (var x = 0; x < 2; x++) {
              console.log("loop iteration: " + x);
              if (flag == true) {
                  console.log("inside if");
                  console.log("will send message to SDK");
                  promises.push(browser.runtime.sendMessage("send-to-sdk").then(reply => {
                      if (reply) {
                          console.log("in webExt: " + reply.content);
                      } else {
                          console.log("<<no response message>>");
                      }
                  });
              } else {
                  console.log("inside else");
              }
          }
          return Promise.all(promises).then(function(){
              //Resolve with an empty Object, which is a valid blockingResponse that permits
              //  the webRequest to complete normally, after it is resolved.
              return {};
          });
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多