在阻塞的 webRequest 处理程序中使用异步调用
Use asynchronous calls in a blocking webRequest handler
总结
我正在使用 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 发送一条消息,但假设它执行一些功能,read/write 操作等。所有 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"]}
);
webRequest.onBeforeRequest
documenation 状态(强调我的):
To cancel or redirect the request, first include "blocking"
in the extraInfoSpec
array argument to addListener()
. Then, in the listener function, return a BlockingResponse
object, setting the appropriate property:
- to cancel the request, include a property
cancel
with the value true.
- to redirect the request, include a property
redirectUrl
with the value set to the URL to which you want to redirect.
From Firefox 52 onwards, instead of returning BlockingResponse
, the listener can return a Promise which is resolved with a BlockingResponse
. This enables the listener to process the request asynchronously.
您似乎已经完成了上述 none。因此,事件是完全异步处理的,不可能将请求延迟到您的处理程序 returns。换句话说,正如目前所写,您的 webRequest.onBeforeRequest
对 webRequest 绝对没有影响。您的处理程序刚刚被告知 webRequest 正在处理中。
为了完成你想要的,延迟请求直到你执行一些异步操作之后,你需要:
将 "webRequestBlocking"
添加到您的 manifest.json 权限:
"permissions": [
"activeTab",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
将 extraInfoSpec
数组参数中的 "blocking"
传递给 addListener()
:
browser.webRequest.onBeforeRequest.addListener(
aMethod,
{urls: ["<all_urls>"],
types: ["main_frame"]},
["blocking"]
);
Return 来自处理程序的 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 {};
});
}
总结
我正在使用 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 发送一条消息,但假设它执行一些功能,read/write 操作等。所有 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"]}
);
webRequest.onBeforeRequest
documenation 状态(强调我的):
To cancel or redirect the request, first include
"blocking"
in theextraInfoSpec
array argument toaddListener()
. Then, in the listener function, return aBlockingResponse
object, setting the appropriate property:
- to cancel the request, include a property
cancel
with the value true.- to redirect the request, include a property
redirectUrl
with the value set to the URL to which you want to redirect.From Firefox 52 onwards, instead of returning
BlockingResponse
, the listener can return a Promise which is resolved with aBlockingResponse
. This enables the listener to process the request asynchronously.
您似乎已经完成了上述 none。因此,事件是完全异步处理的,不可能将请求延迟到您的处理程序 returns。换句话说,正如目前所写,您的 webRequest.onBeforeRequest
对 webRequest 绝对没有影响。您的处理程序刚刚被告知 webRequest 正在处理中。
为了完成你想要的,延迟请求直到你执行一些异步操作之后,你需要:
将
"webRequestBlocking"
添加到您的 manifest.json 权限:"permissions": [ "activeTab", "webRequest", "webRequestBlocking", "<all_urls>" ],
将
extraInfoSpec
数组参数中的"blocking"
传递给addListener()
:browser.webRequest.onBeforeRequest.addListener( aMethod, {urls: ["<all_urls>"], types: ["main_frame"]}, ["blocking"] );
Return 来自处理程序的 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 {}; }); }