Запросы через сервис-работника выполняются дважды - PullRequest
0 голосов
/ 02 мая 2018

Я сделал простой сервисный работник для отсрочки запросов, которые не выполняются для моего JS-приложения (следуя этому примеру ), и он работает хорошо. Но у меня все еще есть проблема, когда запросы успешно выполняются: запросы выполняются дважды. Один раз обычно и один раз служащим из-за звонка 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)
  }
})

Как это сделать хорошо?

EDIT:

Я думаю, мне не нужно повторно fetch() запрос (потому что это является причиной 2-го запроса) и ждать ответа первоначального запроса, который вызвал fetchEvent, но я не знаю, как сделай это. fetchEvent, кажется, не может ждать (и читать) ответ.

Я на правильном пути? Как узнать, когда запрос, вызвавший fetchEvent, получил ответ?

Ответы [ 2 ]

0 голосов
/ 24 июля 2018

Воспроизведение ответа Джеффа Посника, вам нужно позвонить 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.

0 голосов
/ 02 мая 2018

Вы звоните event.respondWith(...) асинхронно, внутри promiseChain.

Вам необходимо вызвать event.respondWith() синхронно во время первоначального выполнения обработчика события fetch. Это «сигнал» работнику службы поддержки о том, что ваш fetch обработчик, а не другой зарегистрированный обработчик fetch (или браузер по умолчанию), предоставит ответ на входящий запрос.

(Пока вы вызываете event.waitUntil(promiseChain) синхронно во время первоначального выполнения, это на самом деле ничего не делает в отношении ответа на запрос - оно просто гарантирует, что работник службы не будет автоматически убит, пока promiseChain выполнения.)

Делая шаг назад, я думаю, что вам, возможно, повезет больше, если вы используете workbox.backgroundSync.Plugin вместе с workbox.routing.registerRoute(), следуя примеру из документов :

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

Это скажет Workbox перехватывать любые POST запросы, которые соответствуют вашему RegExp, пытаться выполнить эти запросы с использованием сети, а в случае сбоя - автоматически ставить в очередь и повторять их через API фоновой синхронизации.

...