拦截获取事件和 return indexedDB 数据

Intercept fetch event and return indexedDB data

我正在使用 service-worker 来缓存一些静态文件,但我也在尝试将我的 json 数据缓存在 indexedDB 中。因此,每当我的应用程序访问 url "www.someurl.com/api/my-items" 时,它就会被服务人员拦截,而是使用我的 indexedDB 数据 return 编辑自定义响应。

我在这里使用基于 promise 的 idb https://github.com/jakearchibald/idb

到目前为止,我想出了以下代码。据我了解,我需要拦截获取事件和 return 自定义响应。

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()" 的响应。我确定有一个我不完全理解的基于承诺的概念。

我会推荐缓存存储 API 使用像 Workbox 这样的辅助库来使事情变得简单。 This SO answer 讨论使用 IndexDB -idb helper 类 与缓存 API - work-box。

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

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

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

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;
                        });
                    })
                );
            }
  });

从索引数据库中读取的方法和return响应

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);
    }
   });

}

希望这对您有所帮助。

OP 要求 "a cleaner way of writing this code, without specifically creating a response with new Response()"。在之前的评论中,我说 "IMO, there's not - a Response has to be explicitly created"。在对这个问题进行了更多思考并在应用程序中自己实施了以下方法之后,我相信有 "a cleaner way of writing this code"。

Google的'Live Data in the Service Worker' states "Once an IndexedDB database is created, data can then be read locally from IndexedDB rather than making network requests to a backend database" (my emphasis) - or, by extension, rather than making requests to a service worker, where, as stated in Google's 'High-performance service worker loading',"you'll end up introducing a small latency hit whenever a network request is made. There's overhead involved in starting up a service worker if it's not already running, and there's also overhead in passing the response from the service worker to the client that made the request.".

因此,一旦 JSON 数据存储在浏览器的 IndexedDB 中,您的应用程序就可以从那里直接访问它,而无需您的应用程序访问URL "www.someurl.com/api/my-items",从而招致service worker中介的开销。 (我们假设从该地址有一个初始网络 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);