santhazh
santhazh

Reputation: 21

redirect: "manual" in fetch redirects to the request URL instead of redirecting to header location in response

I have the below code which am using to get the response header location.

 let callAuthorize = async() => {
        try {
        const authorizeResponse = await fetch(requesturl,
{redirect: "manual", mode:'cors',
        headers: {
          "Cache-Control": "no-store",
          "Accept-Charset": "UTF-8",
          "Access-Control-Expose-Headers": "location"
        }
      });
      if (authorizeResponse.type === "opaqueredirect") {
          window.location.href = authorizeResponse.url;
      }
      }
      catch (e) {
        console.log(e)
      } 

but it redirects to the requesturl instead of redirecting to header location in response.

with normal fetch call am unable to grab the response header, because of CORS issue.

Upvotes: 1

Views: 1619

Answers (1)

charlesroelli
charlesroelli

Reputation: 417

You can't read the redirect location directly. As a workaround, you can navigate the browser to the opaqueredirect response, if you store it in a cache and use a service worker to replay the response. See an example below with one same-origin redirect followed by two cross-origin redirects.

index.html:

<!DOCTYPE html>
<html lang="en">
  <head><title>Navigate to opaqueredirect</title></head>
  <body>
    <button id=button disabled>Navigate to opaqueredirect</button>
  </body>
  <script>
    navigator.serviceWorker.register('sw.js');
    navigator.serviceWorker.ready.then(() => {
        button.disabled = false;
        button.onclick = () => {
            fetch('/redirect1', { redirect: 'manual' }).then(
                (response) => {
                    if (response.type === 'opaqueredirect') {
                        const urlToCache = new URL(response.url);
                        const uuid = crypto.randomUUID();
                        urlToCache.searchParams.set('cacheId', uuid);
                        const requestToCache = new Request(urlToCache);
                        caches.open('cacheId').then((cache) => {
                            cache.put(requestToCache, response).then(() => {
                                window.location.assign(urlToCache);
                            }).catch(console.error);
                        }).catch(console.error);
                    }
                },
            ).catch(console.error);
        };
    });
  </script>
</html>

serve.json:

{
  "redirects": [
      {
          "source": "/redirect1",
          "destination": "/redirect2",
          "type": 302
      },
      {
          "source": "/redirect2",
          "destination": "https://mock.httpstatus.io/307",
          "type": 302
      }
  ]
}

sw.js:

self.addEventListener('fetch', (event) => {
  if (new URL(event.request.url).searchParams.get('cacheId')) {
    event.respondWith(caches.open('cacheId').then(async (cache) => {
      const cacheMatch = await cache.match(event.request);
      if (cacheMatch) {
        cache.delete(event.request).then(() => { }).catch(console.error);
        return cacheMatch;
      }
      return fetch(event.request);
    }));
  }
});

Run npx -y serve in a directory containing the above files, then open localhost:3000 in your browser. Then click the button and the redirect will be followed to https://mock.httpstatus.io/200.

Upvotes: 0

Related Questions