如何在Firefox Service Worker中处理206个响应

时间:2018-07-06 15:05:57

标签: javascript firefox caching http-headers service-worker

在为项目测试服务工作者时,并使用google中的示例:

/*
 Copyright 2016 Google Inc. All Rights Reserved.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

// Names of the two caches used in this version of the service worker.
// Change to v2, etc. when you update any of the local resources, which will
// in turn trigger the install event again.
const PRECACHE = 'precache-v1';
const RUNTIME = 'runtime';

// A list of local resources we always want to be cached.
const PRECACHE_URLS = [
  'index.html',
  './', // Alias for index.html
  'styles.css',
  '../../styles/main.css',
  'demo.js'
];

// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(PRECACHE)
      .then(cache => cache.addAll(PRECACHE_URLS))
      .then(self.skipWaiting())
  );
});

// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
  const currentCaches = [PRECACHE, RUNTIME];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
    }).then(cachesToDelete => {
      return Promise.all(cachesToDelete.map(cacheToDelete => {
        return caches.delete(cacheToDelete);
      }));
    }).then(() => self.clients.claim())
  );
});

// The fetch handler serves responses for same-origin resources from a cache.
// If no response is found, it populates the runtime cache with the response
// from the network before returning it to the page.
self.addEventListener('fetch', event => {
  // Skip cross-origin requests, like those for Google Analytics.
  if (event.request.url.startsWith(self.location.origin)) {
    event.respondWith(
      caches.match(event.request).then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }

        return caches.open(RUNTIME).then(cache => {
          return fetch(event.request).then(response => {
            // Put a copy of the response in the runtime cache.
            return cache.put(event.request, response.clone()).then(() => {
              return response;
            });
          });
        });
      })
    );
  }
});

来源:https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/basic/service-worker.js

我发现Firefox(与野生动物园和Chrome浏览器相反)会在event.waitUntil()以及event.respondWith()内引发错误,如果某些操作不适用于获取请求(即使它只是206部分内容响应) ):

  

服务工作者事件waitUntil()被传递了一个被拒绝的承诺   使用'TypeError:缓存获得基本响应,状态为206,而   尝试添加请求

这种行为破坏了安装程序。如果我这样向安装程序中添加.catch()

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(PRECACHE)
      .then(cache => cache.addAll(PRECACHE_URLS))
      .then(self.skipWaiting())
      .catch(function(err){
        console.log(err);
        self.skipWaiting();
      })
  );

});

我认为前206个将使预缓存停止(?)

然后安装了sw,但是偶尔我会得到一个

  

服务工作者事件responseWith()被传递了一个被拒绝的承诺   使用'TypeError:缓存获得基本响应,状态为206,而   尝试添加请求

即使没有发生,如果我尝试打开指向在安装/预缓存时抛出206错误的URL的链接,则会得到:

  

无法加载“ https://xxxx/yyyyy.mp3”。一种   ServiceWorker向FetchEvent.respondWith()传递了一个承诺,即   拒绝并显示“ TypeError:缓存得到基本响应,状态为206”   在尝试添加请求时   https://xxxx/yyyyy.mp3”。

inside of the browser the error looks like the file is broken

如何正确处理此类错误?像上面那样捕获并没有多大意义,因为它破坏了强制预缓存。即使那是可以接受的,它似乎也会干扰从那时起发生的每个请求,并可能在以后引起麻烦。

1 个答案:

答案 0 :(得分:0)

我可以通过将return语句从cache.put()函数内部移出来解决一半的问题:

self.addEventListener('fetch', event => {
  // Skip cross-origin requests, like those for Google Analytics.
  if (event.request.url.startsWith(self.location.origin)) {
    event.respondWith(
      caches.match(event.request).then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }

        return caches.open(RUNTIME).then(cache => {
          return fetch(event.request).then(response => {
            // Put a copy of the response in the runtime cache.
            cache.put(event.request, response.clone()).then(() => {
              console.log("logged a file into RUNTIME:");
              console.log(response);
            });
            return response; // and return anyhow whatever came back
          });
        });
      })
    );
  }
});

通过这种方式,sw不会等待cache.put()成功,但是大多数时候它都会被缓存。

这解决了最紧迫的问题,但问题仍然存在

a)强制预缓存仍然被206条响应取消 b)如果我想确保请求在运行时被缓存,我仍然需要做一些retry()函数或其他操作。