在阻塞的webRequest处理程序中使用异步调用 [英] Use asynchronous calls in a blocking webRequest handler
问题描述
我正在使用browser.webRequest.onBeforeRequest
处理程序.我需要阻止webRequest,直到获得从处理程序内对异步方法的调用返回的信息为止.我该怎么办?
I'm using a browser.webRequest.onBeforeRequest
handler. I need to block the webRequest until I have information back from calls to asynchronous methods made within the handler. How can I do that?
首先,我对这个长期的问题表示歉意.但我希望有人能提供帮助.
First, my apology for the long question. But I hope someone can help.
我有一个包含browser.webRequest.onBeforeRequest
的嵌入式扩展(我现在需要使用嵌入式扩展来处理一些SDK旧代码).
I have an embedded extension which contains a browser.webRequest.onBeforeRequest
(I need to use embedded extension at the moment to deal with some SDK legacy code).
browser.webRequest.onBeforeRequest
回调函数连接到SDK扩展,并指示其执行某些功能.完成任务后,SDK会将答复发送到webextension.我在browser.runtime.sendMessage
中使用了await
来确保停止执行,直到得到SDK的答复为止.要使用await
,我必须使用async
(但实际上我不希望使用async
函数).当我不使用await
时,我只会在循环完成所有迭代之后才从SDK获得答复,而不是针对每个迭代.
The browser.webRequest.onBeforeRequest
callback function connects to an SDK extension and instructs it to perform some functions. The SDK sends reply to the webextension when it is done from the task. I used await
in the browser.runtime.sendMessage
to ensure that I stop the execution until I get a reply from SDK. To use await
, I had to use async
(but in fact I do not want async
function). When I do not use await
, I only get the reply from the SDK after the loop finishes all its iterations and not for each iteration.
下面的示例代码包含许多控制台消息,这些消息用于调试以仅监视执行情况.
The sample code below contains a lot of console messages for debugging just to monitor the execution.
问题是:我没有得到可靠的结果.在某些情况下(并非全部),http请求在SDK代码生效之前就消失了.我可以确定这一点,因为请求属性必须受到SDK代码的影响.控制台将按预期显示执行顺序.但是,http请求不受SDK的影响(在某些情况下).
The problem is: I am not getting a reliable outcome. In some cases (not all), the http request goes out before the SDK code is effective. I could identify this because the request properties must be affected by the SDK code. The console shows the execution sequence as expected. But, the http request is not affected by the SDK (in some cases).
在这个简单的示例中,SDK只是向网络扩展发送了一条消息,但假定它执行某些功能,读/写操作等.所有SDK任务必须在请求发出之前完成.
In this simple example, the SDK just sends a message to the webextension, but assume that it performs some functions, read/write operations, etc. All the SDK tasks must be completed before the request goes out.
我真正需要的是确保在执行所有SDK代码之前,Web请求不会消失.
What I really need is to guarantee that the web request will NOT go out until all the SDK code is performed.
参考MDN文档,它表示browser.webRequest.onBeforeRequest是async
函数.我想知道这是否是问题的根源?如果是这样,如何强制使其同步?
Reference to MDN documentation, it says that the browser.webRequest.onBeforeRequest is an async
function. I wonder if this is the source of the problem? if so, how to enforce it to be sync?
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"]}
);
推荐答案
The webRequest.onBeforeRequest
documenation states (emphasis mine):
要取消或重定向请求,请首先在
extraInfoSpec
数组参数中将"blocking"
包含在addListener()
中.然后,在监听器函数中,返回BlockingResponse
对象,设置适当的属性:
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:
- 要取消请求,请添加值为true的属性
cancel
. - 要重定向请求,请包含一个属性
redirectUrl
,其值设置为您要重定向到的URL.
- 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.
您似乎没有完成上述任何一项操作.因此,事件是完全异步处理的,不可能将请求延迟到处理程序返回之前.换句话说,如当前所写,您的webRequest.onBeforeRequest
对webRequest绝对没有影响.刚刚通知您的处理程序webRequest正在处理.
You appear to have done none of the above. Thus, the event is handled completely asynchronously, with no possibility of delaying the request until your handler returns. In other words, as currently written, your webRequest.onBeforeRequest
has absolutely no effect on the webRequest. You handler is just notified that the webRequest is in process.
要完成所需的操作,请延迟请求,直到执行一些异步操作之后,您需要:
To accomplish what you desire, delay the request until after you perform some asynchronous operations, you would need to:
-
将
"webRequestBlocking"
添加到您的 manifest.json 权限:
"permissions": [
"activeTab",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
将extraInfoSpec
数组参数中的"blocking"
传递给addListener()
:
Pass "blocking"
in the extraInfoSpec
array argument to addListener()
:
browser.webRequest.onBeforeRequest.addListener(
aMethod,
{urls: ["<all_urls>"],
types: ["main_frame"]},
["blocking"]
);
从处理程序中返回一个Promise,并使用BlockingResponse
进行解析:
Return a Promise from your handler, which resolves with a 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 {};
});
}
这篇关于在阻塞的webRequest处理程序中使用异步调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!