Goal of this task is to intercept a request created by a simple <a href="...">
element, and to add a custom HTTP header into the request. This should be done transparently, without XMLHttpRequest
or similar method which can be problematic if new page is opened or a big file should be downloaded.
To accomplish this, we will:
- Register a Service Worker intercepting requests.
- Augment intercepted requests with a new header, and forward those requests to a server.
To register a Service Worker we have to call the ServiceWorkerContainer.register()
method.
Note that a Service Worker cannot be registered in a HTML page opened with the file://
protocol. It has to be served by a web server.
// index.html
window.addEventListener('load', function () {
navigator
.serviceWorker
.register('/request-interceptor.js')
.then(function (registration) {
console.log('Service worker registered with scope: ', registration.scope);
}, function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
In the Service Worker the FetchEvent
is captured, a request is extracted and augmented with the new X-Custom-Header
header, and forwarded by calling the WindowOrWorkerGlobalScope.fetch()
method.
// request-interceptor.js
self.addEventListener('fetch', function (event) {
event.respondWith(async function () {
let headers = new Headers()
headers.append("X-Custom-Header", "Random value")
return fetch(event.request, {headers: headers})
}());
});
In the Chrome browser, modified requests can be observed in the Developer Tools console on the Network tab.
Note: The origin (referer) of the request is no longer page itself, but the Service Worker itself.
Unfortunately Firefox and Safari does not show augmented requests at this moment. To verify requests are sent correctly we can use tcpdump or we can log requests on a server.
In this example the server is running on the localhost port 8080, so the tcpdump is listening on the loopback lo0
interface.
$ tcpdump -A -i lo0 port 8080
...
9...9...GET /index.html HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/request-interceptor.js
x-custom-header: Random value
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
...