拦截提取事件并返回索引数据库数据



我正在使用服务工作者来缓存一些静态文件,但我也在尝试在索引数据库中缓存我的json数据。因此,每当我的应用程序访问 url "www.someurl.com/api/my-items"时,它都会被服务工作进程截获,取而代之的是,会返回包含我的 indexedDB 数据的自定义响应。

我从这里使用基于承诺的 idb https://github.com/jakearchibald/idb

到目前为止,我想出了以下代码。据我了解,我需要拦截 fetch 事件并返回自定义响应。

importScripts('idb.js');
var pageCache = 'v1';
var idbName = 'data';
var idbTableName = 'idbtable';
var cacheFiles = [
'../js/',
'../css/file1.css',
'../css/fle2.css'
];
//Install and Activate events
//...
//Fetch Event
self.addEventListener('fetch', (event) => {
var requestUrl = new URL(event.request.url);
if (requestUrl.origin !== location.origin) {
//...
if(event.request.url.endsWith('/api/my-items')){
event.respondWith(
idb.open(idbName, 1).then((db) => {
var tx = db.transaction([idbTableName], 'readonly');
var store = tx.objectStore(idbTableName);
return store.getAll();
}).then(function(items) {
return new Response(JSON.stringify(items),  { "status" : 200 , "statusText" : "MyCustomResponse!" })
})
)
} 
//...
}
})

我试图了解是否有一种更简洁的方法来编写此代码,而无需专门使用"new Response(("创建响应。我确信有一个基于承诺的概念我不完全理解。

我遇到了同样的情况,它不是自定义响应,我需要拦截 Http 调用并在索引数据库中查看相同的 URL,我已经推送了 URL 和响应并从那里读取并作为响应给出

在 Service worker fetch 事件中,我实现了网络优先方法,这意味着如果发生任何错误,它将首先查找服务,然后从索引数据库读取并返回响应。

fetch(event.request(.catch(function (result( { }(;

self.addEventListener('fetch', function (event) {
if (event.request.url.includes('[yourservicecallName]')) {
event.respondWith(
fetch(event.request).catch(function (result) {
return readtheDatafromIndexedDb('firstDB', 'firstStore', event.request.url).then(function(response)
{
return response;
});
})
);
}
});

方法从索引数据库读取并返回响应

function readtheDatafromIndexedDb(dbName, storeName, key) {
return new Promise((resolve, reject) => {
var openRequest = indexedDB.open(dbName, 2);
openRequest.onupgradeneeded = function (e) {
let db = request.result;
if (!db.objectStore.contains(storeName)) {
db.createObjectStore(storeName, { autoIncrement: true });
}
}
openRequest.onsuccess = function (e) {
console.log("Success!");
db = e.target.result;
var transaction = db.transaction([storeName], "readwrite");
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onerror = function () {
console.log("Error");
reject("unexpected error happened");
}
request.onsuccess = function (e) {
console.log("return the respose from db");
//JSON.parse(request.result)
resolve(new Response( request.result, { headers: { 'content-type':'text/plain' } } ));
}
}
openRequest.onerror = function (e) {
console.log("Error");
console.dir(e);
}
});
}

希望这对你有帮助。

我会建议使用像Workbox这样的帮助程序库来简化缓存存储API。这个 SO 答案讨论了使用 IndexDB -idb 帮助程序类与缓存 API - 工作盒。

Workbox是领导PWA实施的Chrome团队。此外,WorkBox是他们经过多年学习的新重写的库(来自sw-precache(。值得考虑。

OP 要求"一种更简洁的方式来编写此代码,而无需专门使用new Response()创建响应"。在之前的评论中,我说"IMO,没有 - 必须明确创建Response"。在对这个问题进行了更多思考并在应用程序中自己实现以下方法之后,我相信有"编写此代码的更简洁的方法"。

Google的"Service Worker中的实时数据"指出"一旦创建了IndexedDB数据库,就可以从IndexedDB本地读取数据,而不是向后端数据库发出网络请求"(我的强调( - 或者,通过扩展,而不是向服务工作线程发出请求,正如Google的"高性能服务工作线程加载"中所述,"每当发出网络请求时,您最终都会引入一个小的延迟影响。如果服务工作进程尚未运行,则启动它会产生开销,并且将响应从服务工作进程传递到发出请求的客户端也会产生开销。

因此,一旦 JSON 数据存储在浏览器的 IndexedDB 中,您的应用就可以直接从那里访问它,而无需您的应用访问 URL "www.someurl.com/api/my-items",从而产生服务辅助角色中介的开销。(我们假设该地址有一个初始网络fetch,用于将 JSON 数据加载到 IndexedDB 中。

因此,如果我们从fetch事件处理程序中的respondWith()中提取 IndexedDB 处理代码,则可以使用它来替换应用本身中的fetch调用:

idb.open(idbName, 1).then((db) => {
var tx = db.transaction([idbTableName], 'readonly');
var store = tx.objectStore(idbTableName);
return store.getAll();
})

或者,将Jake Archibald的最新idb实现与async/await一起使用:

const db = await idb.openDB(idbName);
return await db.getAll(idbTableName);

最新更新