【问题标题】:workbox offline response from IDB instead of cache来自 IDB 而不是缓存的工作箱脱机响应
【发布时间】:2025-12-27 05:40:06
【问题描述】:

我正在使用 service worker 构建一个 vueJs 应用程序。我决定使用 Workbox 和 InjestManifest 方法来拥有自己的路线。

在线获取时: 1-用网络回答 2- 将正文写入 IDB(通过 localforage) 3- 发回响应

这里一切正常,sw 拦截 fetch 并返回适当的响应,IDB 包含正确的详细信息。 在线时发送回 fecth 的响应: 响应 {type: "cors", url: "http://localhost:3005/api/events", redirected: false, status: 200, ok: true, ...}

问题是当我离线时。 我的意图是连接到 Locaforage 并检索内容并建立响应。 问题是 Fetch 认为此响应不合适,然后拒绝它。 Console.log 确认 sw 中的 .catch 正在工作,但看起来它发送的响应被拒绝了。 这是我在离线时发送回获取的响应的 console.log; 响应 {type: "default", url: "", redirected: false, status: 200, ok: true, ...}

我不知道 fetch 是否不满意,因为响应的 url 与请求上的不同,但工作箱应该允许响应来自缓存或 fetch 的响应之外的其他响应。

这里是代码

importScripts('localforage.min.js')

localforage.config({
  name: 'Asso-corse'
})
workbox.skipWaiting()
workbox.clientsClaim()

workbox.routing.registerRoute(
  new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
  workbox.strategies.cacheFirst({
    cacheName: 'googleapis',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 30
      })
    ]
  })
)
workbox.routing.registerRoute( new RegExp('http://localhost:3005/api/'), function (event) {
  fetch(event.url)
    .then((response) => {
      var cloneRes = response.clone()
      console.log(cloneRes)
      cloneRes.json()
      .then((body) => {
        localforage.setItem(event.url.pathname, body)
      })
      return response
    })
    .catch(function (error) {
      console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
        localforage.getItem(event.url.pathname)
        .then((res) => {
         let payload = new Response(JSON.stringify(res), { "status" : 200 , 
    "statusText" : "MyCustomResponse!" })
         console.log(payload)
        return payload
        })
  })
    })
workbox.precaching.precacheAndRoute(self.__precacheManifest || [])

我真的被困在那里,因为工作箱上的所有文档都与利用缓存有关。我正在利用 localforage,因为它支持使离线功能正常工作所需的 Promise。

谢谢

【问题讨论】:

  • 我正在利用 localforage,因为它支持使离线功能正常工作所需的 Promise。 你能解释一下你的意思吗? Cache Storage API 也使用 Promise 并异步操作,它绝对是为处理这种用例而设计的。
  • 我提到这个是为了解释为什么我使用 Localforage 而不是 IDB。但我想利用这种存储,因为它也是标准建议的一部分 (developers.google.com/web/ilt/pwa/…):“数据存储的一般准则是 URL 可寻址资源应与 Cache 接口一起存储,而其他数据应与 IndexedDB 一起存储。例如 HTML、CSS 和 JS 文件应该存储在缓存中,而 JSON 数据应该存储在 IndexedDB 中。”我知道缓存存储会让我的生活更轻松。
  • URL 可寻址资源应与 Cache 接口一起存储...您的 JSON 数据源自 HTTP API,并具有相应的 URL(以 /api/ 路径开头在您的示例中),因此它是可寻址的 URL。对于这个用例,我建议坚持使用 Cache Storage API。
  • 感谢 Jeff,这当然是我要做的,但我很惊讶地发现与 IDB 的集成在任何地方都没有涉及,因为它是维护本地数据库的标准方法的一部分。 API 是我正在构建的后端,我何时必须发布数据。我的计划也是利用 service worker 来同步数据。维护一个干净的 IDB 存储是有意义的。
  • @GeraldM:我在我的一个本地项目(角度为 6)中的设置与您的设置相同,例如在离线模式下使用 localforage 作为后备响应进行阅读。唯一的事情是我在 firebase API 上有 registerroute。捕获处理程序确实被调用,但我的自定义响应失败。我也在回复回复。但它仍然无法正常工作。任何想法 ?我正在本地主机上尝试这个,而不是现场环境。

标签: response workbox localforage


【解决方案1】:

您的catch() 处理程序需要返回Response 对象或Response 对象的承诺。

稍微调整一下你的示例代码的格式,你正在做:

.catch(function (error) {
  console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
  localforage.getItem(event.url.pathname).then((res) => {
    let payload = new Response(JSON.stringify(res), { "status" : 200 , "statusText" : "MyCustomResponse!" })
    console.log(payload)
    return payload
  })
})

基于这种格式,我认为更清楚的是,您没有从 catch() 处理程序中返回 Response 或对 Response 的承诺 - 您根本没有返回任何内容。

在您的 localforage.getItem(...) 语句之前添加 return 应该可以解决这个问题:

.catch(function (error) {
  console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
  return localforage.getItem(event.url.pathname).then((res) => {
    let payload = new Response(JSON.stringify(res), { "status" : 200 , "statusText" : "MyCustomResponse!" })
    console.log(payload)
    return payload
  })
})

但是,正如您在原始问题的 cmets 中所述,我认为没有必要使用 IndexedDB 存储这种类型的 URL 可寻址数据。在存储和检索从 HTTP API 获得的 JSON 数据时,您可以只依赖 Cache Storage API,Workbox 默认会愉快地使用它。

【讨论】:

  • 成功了,非常感谢。我将明确地创建另一个利用缓存存储 API 的版本,看看它是否涵盖了应用程序必须涵盖的所有用例。
  • 您好 Jeff,我必须承认缓存存储 API 做得很好。一行代码然后就完成了。通过这次经历,我学到了很多东西,重要的是要通过实验来了解哪些选项最有价值。到目前为止,Workbox 运行良好。
  • 很高兴听到这个消息!
  • 嗨@JeffPosnick。我们正在尝试使应用程序离线。但是我们使用的是 SOAP API,并且对于我们的应用程序触发的任何 Web 服务,URL 端点总是相同的。在这种情况下,如果用户离线,我们应该如何处理 API 响应。由于缓存 API 是基于 URL 的,有没有办法使用缓存 API 来处理这种情况?