Description
Library Affected:
"workbox-background-sync": "^6.5.3",
"workbox-core": "^6.5.3",
"workbox-precaching": "^6.5.3",
"workbox-window": "^6.5.3"
Browser & Platform:
all browsers
Issue or Feature Request Description:
I have noticed 2 issues with handlerDidError
callback.
Base code:
import { Queue } from "workbox-background-sync";
import { Strategy, NetworkOnly } from "workbox-strategies";
const queue = new Queue("myQueueName", {
onSync: async ({ queue }) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
var response = await fetch(entry.request.clone());
} catch (error) {
await queue.unshiftRequest(entry);
throw error;
}
}
},
});
const statusPlugin = {
handlerWillRespond: async ({ request, response, event, state }) => {
console.log("handlerWillRespond");
return response;
},
fetchDidFail: async ({ originalRequest, request, error, event }) => {
console.log("fetchDidFail");
//console.log(await originalRequest.clone().json()); // works
await queue.pushRequest({ request: originalRequest });
},
fetchDidSucceed: async ({ response }) => {
console.log("fetchDidSucceed");
//console.log(await response.clone().json()); // works
return response;
},
handlerDidError: async ({ error, event, request, state }) => {
console.log("handlerDidError");
//console.log(await request.clone().json()); // TypeError: Failed to execute 'clone' on 'Request': Request body is already used
},
};
registerRoute(
new RegExp(".*/Exercises/.*"),
new NetworkOnly({
networkTimeoutSeconds: 3,
plugins: [statusPlugin],
}),
"POST"
);
Issue 1: Unable to read the request data
Following code:
handlerDidError: async ({ error, event, request, state }) => {
console.log("handlerDidError");
console.log(await request.clone().json()); // TypeError: Failed to execute 'clone' on 'Request': Request body is already used
},
will throw:
TypeError: Failed to execute 'clone' on 'Request': Request body is already used
Issue 2: handlerDidError
runs before fetchDidFail
(subjective)
Current callback flow is:
- client makes a request
- network is unavailable
handlerDidError
is consoled- clients gets the response
fetchDidFail
is consoled
I would expect all the pipelines related to errors to be executed before client sees the response.
Temporary solution
I have managed to fix both of the problems by using the custom Network strategy
class NewStrategy extends NetworkOnly {
async _handle(request, handler) {
return await handler.fetch(request.clone());
}
}
See that I have cloned the request before passing it to handler. This will allow us to clone the request later in handlerDidError
callback. The second "issue" is also solved. Now the flow is:
- client makes a request
- network is unavailable
fetchDidFail
is consoledhandlerDidError
is consoled- clients gets the response
See that the handlerDidError
is actually run After the fetchDidFail
. This makes sense because the handlerDidError
is supposed to be the last logical thing in the pipeline: https://developer.chrome.com/docs/workbox/using-plugins/
handlerDidError: Called if the handler can't provide a valid response from from any source, which is the optimal time to provide some sort of fallback response as an alternative to failing outright.
// Returnresponse
, a differentResponse
object as a fallback, ornull
.
I might be wrong about the pipeline order thingy (it just looks more logical to me) but the "cloning" issue seems to be a valid one regardless.