通过 service-worker 的请求被执行两次

2022-01-20 00:00:00 fetch javascript service-worker workbox

我已经做了一个简单的服务工作者来推迟我的 JS 应用程序失败的请求(遵循 this example) 并且效果很好.但是当请求成功时我仍然有一个问题:请求完成了两次.我猜是由于 fetch() 调用,一次正常,一次由服务人员执行.

I've done a simple service-worker to defer requests that fail for my JS application (following this example) and it works well. But I still have a problem when requests succeed: the requests are done twice. One time normaly and one time by the service-worker due to the fetch() call I guess.

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

It's a real problem because when the client want to save datas, they are saved twice...

代码如下:

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 似乎无法等待(并读取)响应.

I think I don't have to re-fetch() the request (because THIS is the cause of the 2nd request) and wait the response of the initial request that triggered the fetchEvent but I have no idea how to do it. The fetchEvent seems to have no way to wait (and read) the response.

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

Am I on the right way ? How to know when the request that triggered the fetchEvent has a response ?

推荐答案

捎带 Jeff Posnick 的答案,你需要调用 event.respondWith() 并包含 fetch() 在它的 async function() 内部调用.

Piggybacking Jeff Posnick's answer, you need to call event.respondWith() and include the fetch() call inside it's 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 调用时遇到的问题.

This will avoid the issue you're having with the second ajax call.

相关文章