I'd like to intercept fetch from all parts and libraries in my application, and at the same time I'd like not to break possibility of working with the application via file URL - it is useful for Electron and mobile devices (via WebView). For now, I've found two possible ways of doing this:
something like here
const realFetch = window.fetch;
window.fetch = function() {
// do something
return realFetch.apply(this, arguments)
}
something like here, with service worker registration:
main.js:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('sw.js').then(function(registration) {
console.log('Service worker registered with scope: ', registration.scope);
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
sw.js:
self.addEventListener('fetch', function(event) {
event.respondWith(
// intercept requests by handling event.request here
);
});
With the first approach I cannot intercept fetch requests from web workers. The second approach doesn't work with file URLs, and I want my application to work via file URL due to it allows me to use the app via Electron for desktops or WebView for Android. Is there any other way for intercepting fetch requests?
P.S. I cannot modify the worker I'm trying to intercept requests from.
Update: On basis of @Ciro Corvino's answer, I've tried the third approach: to start my own worker before anythnig else and try to redefine fetch from there. Didn't work for me, unfortunately, here is the code:
function redefineFetch() {
console.log('inside worker');
if (self.fetch == null) {
console.log('null!');
} else {
console.log(self.fetch.toString());
}
const originalFetch: WindowOrWorkerGlobalScope['fetch'] = self.fetch;
self.fetch = (input: RequestInfo, init: RequestInit) => {
console.log('overridden');
return originalFetch(input, init);
}
}
const blob = new Blob(['(' +
redefineFetch.toString() + ')()'], {type: 'text/javascript'});
const blobUrl = window.URL.createObjectURL(blob);
const w = new Worker(blobUrl);
I'm sure that this code starts before the other workers (I've added a timeout), but this doesn't redefine fetch for the other workers. Can someone explain why or fix the solution?
Update 2: Apparently each worker has it's own private WorkerGlobalScope, otherwise there would be no sense to use messages for inter-worker communications. Probably, another fix for my problem could be in overriding Worker constructor, if this is possible. Will check it.
To intercept HTTP requests, use the webRequest API. This API enables you to add listeners for various stages of making an HTTP request. In the listeners, you can: Get access to request headers and bodies and response headers.
Using Service Workers, you can build your own custom HTTP responses, including editing their headers. This functionality makes Service Workers extremely powerful—which is why you can understand that they need to serve requests over HTTPS.
The Fetch API doesn't support interceptors natively. However, there are other libraries for making HTTP calls that support interceptors.
Service Workers are a special type of Web Worker with the ability to intercept, modify, and respond to all network requests using the Fetch API. Service Workers can access the Cache API, and asynchronous client-side data stores, such as IndexedDB , to store resources.
Just try to override the fetch method of the current WorkerGlobalScope
into main javascript context (window
) and into each js file run in a dedicated worker context calling this function:
note that the
self
property returns the specialized scope for each context
//works in each worker context you call it and enable fetch interception
function EnableFetchWithArguments() {
const originalCtxFetch = self.fetch;
self.fetch = function() {
// Get the parameter in arguments
// Intercept the parameter here
return originalCtxFetch.apply(this, arguments)
}
}
see for reference and browser compatiblity: WorkerGlobalScope
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With