简体   繁体   中英

Service Worker breaking 301 redirects

I'm using a service worker on a WordPress site and it's messing up the redirections from https://example.com/page to https://example.com/page/ .

After the first load, going to the URL without the trailing slash Blink browsers say "This site can't be reached" and Firefox says "Corrupted content error".

Based on my reading of https://medium.com/@boopathi/service-workers-gotchas-44bec65eab3f#.hf3r4pbcs and How to alter the headers of a Request? I think I have to detect when a response is 3xx and set the redirect mode to manual.

However nothing I've tried based on my research has worked. How do I fix this?

Current service worker file:

var cacheName = 'v14';

var urlsToCache = [
  // list of URLs to precache
];

self.addEventListener('install', event => {

  function onInstall(event) {
    return caches.open(cacheName)
      .then(cache => cache.addAll(urlsToCache));
  }

  event.waitUntil(
    onInstall(event)
      .then(() => self.skipWaiting())
  );

});

self.addEventListener('activate', event => {

  function onActivate (event) {
    return caches.keys()
      .then(cacheKeys => {
        var oldCacheKeys = cacheKeys.filter(key => key.indexOf(cacheName) !== 0);
        var deletePromises = oldCacheKeys.map(oldKey => caches.delete(oldKey));
        return Promise.all(deletePromises);
      })
  }

  event.waitUntil(
    onActivate(event)
      .then(() => self.clients.claim ())
  );
});

self.addEventListener('fetch', event => {

  function onFetch (event) {
    // Let's not interfere with requests for stuff that doesn't need to be cached
    // or could prevent access to admin if it is
    if (event.request.url.match(/wp-admin/) || event.request.url.match(/wp-login/) || event.request.url.match(/preview=true/) || event.request.url.match(/wp-includes/) || event.request.url.match(/plugins/) || event.request.url.match(/google-analytics/) || event.request.url.match(/gravatar\.com/) || event.request.url.match(/login/) || event.request.url.match(/admin/) || event.request.method !== 'GET') {
      return;
    }

    // Determine type of asset
    var request = event.request,
        acceptHeader = request.headers.get('Accept'),
        resourceType = 'static';

    if(acceptHeader.indexOf('text/html') !== -1) {
      resourceType = 'content';
    } else if(acceptHeader.indexOf('image') !== -1) {
      resourceType = 'image';
    }

    // Network first for HTML and images
    if(resourceType === 'content') {
      event.respondWith(fetch(request.url, {
        method: request.method,
        headers: request.headers,
        mode: 'same-origin', // need to set this properly
        credentials: request.credentials,
        redirect: 'manual'
      })
        .then(response => addToCache(request, response)) // read through caching
        .catch(() => fetchFromCache(event))
        .catch(() => offlineResponse(resourceType))
      )
    }

    // Cache first for static assets
    else if(resourceType === 'static' || resourceType === 'image') {
      event.respondWith(fetchFromCache(event)
        .catch(() => fetch(request))
        .then(response => addToCache(request, response))
        .catch(() => offlineResponse(resourceType))
      )
    }
  }

  onFetch(event);

});

function addToCache(request, response) {

  if(response.ok) { // only 200s
    var copy = response.clone(); // Because responses can only be used once
    caches.open(cacheName)
      .then(cache => {
        cache.put(request, copy);
      });

    return response;
  }

}

function fetchFromCache (event) {

  return caches.match(event.request)
    .then(response => {
      if(!response) {
        // A synchronous error that will kick off the catch handler
        throw Error('${event.request.url} not found in cache');
      }
    return response;
  });

}

function offlineResponse (resourceType) {

  if(resourceType === 'content') {
    return caches.match('/offline/');
  }
  return undefined;

}

When encountering error with particular site, I suggest to clear your browser cache and delete your saved cookies for the site first. Corrupted Content Error can be caused by running outdated software in the server.

Things to note about a service worker is that, it is a JavaScript worker . So, it cant access the DOM directly. Instead, a service worker can communicate with the pages it controls by responding to messages sent via the postMessage.

You don't need to do anything to follow redirects. If requesting some/url and being redirected to some/url/ the serviceo worker should be able to get the proper response.

But if you want to manually handle the 3XX answer you can do:

self.onfetch = function (event) {
  var dontFollowRedirects = new Request(event.request.url, { redirect: 'manual' });
  event.respondWith(fetch(dontFollowRedirects)
    .then(function (response) {
      if (response.status >= 300 && response.status < 400) {
        return doSomethingWithRedirection(response);
      }
    })
  );
}

Try this on a clean state, wiping out your caches and pre-installed Service Workers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM