我正在使用服务工作人员为我拦截请求,并通过与 Web 工作人员(也从同一父页面创建)通信来提供对获取请求的响应。我使用消息通道在工作人员和服务人员之间进行直接通信。这是我写的一个简单的 POC:
var otherPort, parentPort;
var dummyObj;
var DummyHandler = function()
{
this.onmessage = null;
var selfRef = this;
this.callHandler = function(arg)
{
if (typeof selfRef.onmessage === "function")
{
selfRef.onmessage(arg);
}
else
{
console.error("Message Handler not set");
}
};
};
function msgFromW(evt)
{
console.log(evt.data);
dummyObj.callHandler(evt);
}
self.addEventListener("message", function(evt) {
var data = evt.data;
if(data.msg === "connect")
{
otherPort = evt.ports[1];
otherPort.onmessage = msgFromW;
parentPort = evt.ports[0];
parentPort.postMessage({"msg": "connect"});
}
});
self.addEventListener("fetch", function(event)
{
var url = event.request.url;
var urlObj = new URL(url);
if(!isToBeIntercepted(url))
{
return fetch(event.request);
}
url = decodeURI(url);
var key = processURL(url).toLowerCase();
console.log("Fetch For: " + key);
event.respondWith(new Promise(function(resolve, reject){
dummyObj = new DummyHandler();
dummyObj.onmessage = function(e)
{
if(e.data.error)
{
reject(e.data.error);
}
else
{
var content = e.data.data;
var blob = new Blob([content]);
resolve(new Response(blob));
}
};
otherPort.postMessage({"msg": "content", param: key});
}));
});
端口的作用:
otherPort : 与工作人员的通信
parentPort : 与父页面通信
在工人中,我有一个数据库这样说:
var dataBase = {
"file1.txt": "This is File1",
"file2.txt": "This is File2"
};
Worker 只是根据 Service Worker 发送的密钥提供正确的数据。实际上,这些将是非常大的文件。
我面临的问题如下:
- 由于我使用的是全局 dummyObj,因此旧的 dummyObj 以及旧的 onmessage 都会丢失,并且只有最新的资源会用接收到的数据进行响应。
- 实际上,file2 得到
This is File1
了 ,因为最新的 dummyObj 是为 file2.txt 的,但工作人员首先为 file1.txt 发送数据。
我尝试通过直接创建 iframe 并拦截其中的所有请求:
<html>
<head></head>
<body><iframe src="tointercept/file1.txt" ></iframe><iframe src="tointercept/file2.txt"></iframe>
</body>
</html>
一种方法是在创建 iframe 之前将所有可以提取到工作程序中的 IndexedDB 的文件写入。然后在 Service Worker 中从索引数据库中获取那些。但我不想将所有资源都保存在 IDB 中。所以这种方法不是我想要的。
有人知道以其他方式完成我想做的事情的方法吗?或者有没有解决我正在做的事情。
请帮忙!
更新
我通过在全局队列中排队 dummyObjs 而不是拥有全局对象来实现这一点。在收到来自工作人员的响应后,msgFromW
我从队列中弹出一个元素并调用它的callHandler
函数。但我不确定这是否是一个可靠的解决方案。因为它假设一切都会按顺序发生。这个假设正确吗?