Service Worker нарушает 301 редирект

Я использую сервис-воркер на сайте WordPress, и он мешает перенаправлению с https://example.com/page на https://example.com/page/.

После первой загрузки при переходе по URL без косой черты браузеры Blink говорят: «Этот сайт недоступен», а Firefox сообщает «Ошибка поврежденного содержимого».

На основе моего чтения https://medium.com/@boopathi/service-workers-gotchas-44bec65eab3f#.hf3r4pbcs и Как изменить заголовки запроса? Я думаю, что мне нужно определить, когда ответ равен 3xx, и установить ручной режим перенаправления.

Однако ничего из того, что я пробовал на основе моих исследований, не сработало. Как это исправить?

Текущий рабочий файл службы:

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;

}

person Derek Johnson    schedule 08.11.2016    source источник
comment
Можете ли вы немного сократить тестовый пример? Там довольно много всего происходит. Я подозреваю, что addToCache() ничего не вернет, если! Response.ok (например, при перенаправлении). Кроме того, вы можете захотеть event.respondWith(fetch(request)), поскольку, похоже, вы не преобразуете запрос?   -  person mjs    schedule 09.11.2016
comment
Ваши подозрения были вполне обоснованными. Вынесение возврата за пределы if исправило это. Спасибо :)   -  person Derek Johnson    schedule 21.11.2016


Ответы (2)


Вам не нужно ничего делать, чтобы следовать перенаправлениям. При запросе some/url и перенаправлении на some/url/ рабочий сервисо должен иметь возможность получить правильный ответ.

Но если вы хотите вручную обработать ответ 3XX, вы можете сделать:

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);
      }
    })
  );
}

Попробуйте это в чистом состоянии, очистив кеши и предварительно установленных Service Workers.

person Salva    schedule 10.11.2016

При обнаружении ошибки на определенном сайте я предлагаю очистить кеш вашего браузера и сначала удалить сохраненные файлы cookie для этого сайта. Ошибка поврежденного содержимого может быть вызвана устаревшим программным обеспечением на сервере.

Следует отметить, что обслуживающий персонал, это рабочий JavaScript. Таким образом, он не может напрямую получить доступ к DOM. Вместо этого сервисный работник может общаться со страницами, которые он контролирует, отвечая на сообщения, отправленные через postMessage.

person Android Enthusiast    schedule 09.11.2016