Запросы через сервис-работника выполняются дважды
Я сделал простой сервисный работник, чтобы отложить запросы, которые терпят неудачу для моего приложения 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)
}
})
Как это сделать хорошо?
РЕДАКТИРОВАТЬ:
Я думаю, мне не нужно повторно fetch()
запрос (потому что это является причиной 2-го запроса) и ждать ответа первоначального запроса, который вызвал fetchEvent
но я понятия не имею, как это сделать. fetchEvent
кажется, нет возможности ждать (и читать) ответ.
Я на правильном пути? Как узнать, когда запрос вызвал fetchEvent
есть ответ?
2 ответа
Ты звонишь 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 фоновой синхронизации.
Прислушиваясь к ответу Джеффа Посника, вам нужно позвонить 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.