【问题标题】:Intercept fetch event and return indexedDB data拦截 fetch 事件并返回 indexedDB 数据
【发布时间】:2018-06-03 16:45:35
【问题描述】:

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

我从这里使用基于 promise 的 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()”创建响应。我确信有一个我不完全理解的基于承诺的概念。

【问题讨论】:

  • 嗨 Roman,您是否成功拦截并从 indexed-db 获取数据并作为响应返回。
  • @Aji Roman 并没有寻找从 IndexedDb 获取数据并作为响应返回的成功方法——他的代码已经成功地做到了这一点。他在问是否有一种更清洁的方式来做这件事,而不是专门创建一个响应。 IMO,没有 - 必须明确创建响应。但我愿意纠正!

标签: service-worker progressive-web-apps pwa


【解决方案1】:

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

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

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

}

希望这会对您有所帮助。

【讨论】:

  • 这并没有回答 OP 的问题,该问题要求“以更简洁的方式编写此代码,而无需专门使用 new Response() 创建响应。”这个答案使用new Response()
【解决方案2】:

我会推荐使用像 Workbox 这样的辅助库来简化缓存存储 API。 This SO answer 讨论使用 IndexDB -idb 助手类与缓存 API - 工作箱。

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

【讨论】:

  • 这并没有解决 OP 的问题。正如SO answer 所述,Workbox 只是“将 IndexedDB 用于一些带外管理信息,例如时间戳”,而不是用于在 indexedDB 中缓存 JSON 数据,这是 OP 的要求。
【解决方案3】:

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

Google 的 'Live Data in the Service Worker' 声明“一旦创建了 IndexedDB 数据库,就可以从 IndexedDB 本地读取数据,而不是向后端数据库发出网络请求”(我的重点)——或者,通过扩展,而不是向服务工作者发出请求,正如谷歌的'High-performance service worker loading' 中所述,“无论何时发出网络请求,你最终都会引入一个小的延迟命中。如果不是,启动服务工作者会产生开销已经在运行,并且将服务工作者的响应传递给发出请求的客户端也会产生开销。”。

因此,一旦 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);

【讨论】:

    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 2021-06-27
    相关资源
    最近更新 更多