3

So I have a service worker for fetch:

self.addEventListener('fetch', (event) => {
    const requestProcessor = (idToken) => {
        let req = event.request;
        // For same origin https requests, append idToken to header.
        if ((self.location.protocol === 'https:' ||
            self.location.hostname === 'localhost') &&
            idToken) {

            // Clone headers as request headers are immutable.
            const headers = new Headers();
            for (let entry of req.headers.entries()) {
                headers.append(entry[0], entry[1]);
            }

            // Add ID token to header.
            headers.append('Authorization', self.location.origin === getOriginFromUrl(event.request.url) ? `Bearer ${idToken}` : idToken);
            try {
                req = new Request(req.url, {
                    method: req.method,
                    headers: headers,
                    mode: self.location.origin === getOriginFromUrl(event.request.url) ? 'same-origin' : req.mode,
                    credentials: req.credentials,
                    cache: req.cache,
                    redirect: req.redirect,
                    referrer: req.referrer,
                    body: req.body,
                    bodyUsed: req.bodyUsed,
                    context: req.context
                });
            } catch (e) {
                console.error(e);
            }
        }

        return fetch(req);
    };

    event.respondWith(getIdToken().then(requestProcessor));
});

It is being called in another file like so:

export const makePostRequest = (url = '', params = {}) => {
    return fetch(url, {
        method: 'POST',
        body: JSON.stringify(params),
        headers: {
            'Content-type': 'application/json'
        }
    }).then((res) => res).catch((err) => console.log(err));
};

For some reason, the req.body is always undefined inside of the service worker. Furthermore, it looks like the fetch request happens twice. When I put a breakpoint and step through the code, I can see that nothing from the fetch is being picked up by the service worker. I don't understand.

codehitman
  • 1,148
  • 11
  • 33
  • https://stackoverflow.com/questions/37704641/access-dom-by-web-worker – RenaissanceProgrammer Aug 21 '19 at 01:04
  • 1
    @RenaissanceProgrammer Not sure which part of the post you want me to look at. But it doesn't seem relevant to me. – codehitman Aug 21 '19 at 01:25
  • my understanding is that your res.body is coming from req.body and Request.body is the body of the DOM which is is not accessible from a worker, is that not correct? – RenaissanceProgrammer Aug 21 '19 at 17:39
  • 1
    @RenaissanceProgrammer My bad, it's `req.body` inside of the service worker. To answer your question, no, there's nothing coming from the DOM. The `makePostRequest` is being called once the user clicks on a button; the app POSTs to a URL, where the body is an object that is retrieved from Redux. For some inexplicable reason, none of the other options in the `fetch` (like headers, etc.) are being intercepted by the service worker listening for `fetch`. – codehitman Aug 21 '19 at 22:18
  • 1
    Based on this post: https://stackoverflow.com/a/54016415 I have added a `mode:'cors'`, but still no dice. – codehitman Aug 22 '19 at 20:06

2 Answers2

2

Okay, so this isn't obvious. So after some research this solved my issue:

self.addEventListener('fetch', (event) => {
    if (getOriginFromUrl(event.request.url) === 'https://app.example.com') {
        const requestProcessor = (idToken) => {
            let newRequest = null;

            // For same origin https requests, append idToken to header.
            if ((self.location.protocol === 'https:' || self.location.hostname === 'localhost') && idToken) {
                try {
                    newRequest = new Request(event.request, {
                        headers: new Headers({
                            ...event.request.Headers,
                            'Content-Type': 'application/json',
                            Authorization: 'Bearer ' + idToken,
                        })
                    })
                } catch (e) {
                    console.log(e);
                }
            }

            return fetch(newRequest);
        };

        /*  Fetch the resource after checking for the ID token.
            This can also be integrated with existing logic to serve cached files
            in offline mode.*/
        event.respondWith(getIdToken().then(requestProcessor, requestProcessor));
    }
});

I also had to set the mode:

export const makePostRequest = (url = '', params = {}) => {
    return fetch(url, {
        method: 'POST',
        mode: 'cors',
        headers: {
            'Content-type': 'application/json'
        },
        body: JSON.stringify(params)
    }).then((res) => res).catch((err) => console.log(err));
};

There were two issues:

  1. By default the header's mode was set to no-cors. According to a previous SO answer, I had to set the mode to cors to allow for non-basic headers which would also include body.
  2. The other issue had to do with the headers being immutable. This had to be changed to copy properly.
codehitman
  • 1,148
  • 11
  • 33
  • Can you elaborate on *what* specifically solved your issue? I don't see you using the request body here. Is it just that in your case, you don't require it anymore? – Brad Apr 24 '20 at 23:10
-1

The Request object will implement methods like .blob().

await req.blob()
Brad
  • 159,648
  • 54
  • 349
  • 530