【问题标题】:Requests through service-worker are done twice通过 service-worker 的请求被执行两次
【发布时间】:2022-03-16 19:49:27
【问题描述】:

我已经完成了一个简单的 service-worker 来推迟我的 JS 应用程序失败的请求(在 this example 之后),它运行良好。 但是当请求成功时我仍然有一个问题:请求完成了两次。由于fetch() 电话,我猜是正常一次,一次由服务人员调用。

这是一个真正的问题,因为当客户端要保存数据时,它们会被保存两次......

代码如下:

const queue = new workbox.backgroundSync.Queue('deferredRequestsQueue');
const requestsToDefer = [
  { urlPattern: /\/sf\/observation$/, method: 'POST' }
]
function isRequestAllowedToBeDeferred (request) {
  for (let i = 0; i < requestsToDefer.length; i++) {
    if (request.method && request.method.toLowerCase() === requestsToDefer[i].method.toLowerCase()
      && requestsToDefer[i].urlPattern.test(request.url)) {
      return true
    }
  }
  return false
}

self.addEventListener('fetch', (event) => {
  if (isRequestAllowedToBeDeferred(event.request)) {
    const requestClone = event.request.clone()
    const promiseChain = fetch(requestClone)
      .catch((err) => {
        console.log(`Request added to queue: ${event.request.url}`)
        queue.addRequest(event.request)

        event.respondWith(new Response({ deferred: true, request: requestClone }))
      })

    event.waitUntil(promiseChain)
  }
})

如何做好?

编辑:

我认为我不必重新fetch() 请求(因为这是第二次请求的原因)并等待触发fetchEvent 的初始请求的响应,但我不知道如何做。 fetchEvent 似乎无法等待(并读取)响应。

我走对了吗?如何知道触发fetchEvent的请求何时有响应?

【问题讨论】:

  • 双重请求的原因 - 客户端发出请求,获取侦听器看到它并发出第二个请求(根据您的说明)。为了防止这种情况,请从 catch 内部删除 response with,在 waitUntil 添加 event.respondWith(promiseChain) 和你完成。因此,您的侦听器监视、接管、发出请求、向客户端发送返回调整后的承诺。

标签: javascript service-worker fetch-api workbox


【解决方案1】:

您在 promiseChain 内部异步调用 event.respondWith(...)

您需要在fetch 事件处理程序的初始执行期间同步调用event.respondWith()。这是给服务工作者的“信号”,它是您的 fetch 处理程序,而不是另一个注册的 fetch 处理程序(或浏览器默认处理程序)将为传入请求提供响应。

(虽然您在初始执行期间同步调用event.waitUntil(promiseChain),但实际上并没有对响应请求做任何事情——它只是确保服务工作者不会在promiseChain 被自动终止时被杀死执行。)

退后一步,我认为如果您使用workbox.backgroundSync.Pluginworkbox.routing.registerRoute() 并遵循example from the docs,可能会更好地完成您想做的事情:

workbox.routing.registerRoute(
  /\/sf\/observation$/,
  workbox.strategy.networkOnly({
    plugins: [new workbox.backgroundSync.Plugin('deferredRequestsQueue')]
  }),
  'POST'
);

这将告诉 Workbox 拦截任何与您的 RegExp 匹配的 POST 请求,尝试使用网络发出这些请求,如果失败,自动排队并通过后台同步 API 重试它们。

【讨论】:

  • 好的,但是使用 backgroundSync 插件,我的应用程序可以检测到请求失败但被服务人员推迟了吗?
【解决方案2】:

捎带 Jeff Posnick 的回答,您需要拨打 event.respondWith() 并将 fetch() 呼叫包含在 async function() 中。

例如:

self.addEventListener('fetch', function(event) {
    if (isRequestAllowedToBeDeferred(event.request)) {
        event.respondWith(async function(){
            const promiseChain = fetch(event.request.clone())
                .catch(function(err) {
                    return queue.addRequest(event.request);
            });
            event.waitUntil(promiseChain);
            return promiseChain;
        }());
    }
});

这将避免您在第二次 ajax 调用时遇到的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 2021-06-01
    • 1970-01-01
    • 2013-03-08
    • 2017-10-21
    • 2018-07-27
    相关资源
    最近更新 更多