Service Worker用法, 跨域与踩坑记录

1,786 阅读2分钟

参考

简易用法, 甚至可以直接复制粘贴使用

在主线程中安装

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js')
}

sw.js

const VERSION = 'v1';

// 缓存
self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open(VERSION).then(function (cache) {
      return cache.addAll([]);
    })
    self.skipWaiting()
  );
});

// 删除旧版本sw的缓存
self.addEventListener('activate', function (event) {
  console.log('service worker activate');
  event.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames.map(function (cacheName) {
          // 如果当前版本和缓存版本不一致
          if (cacheName !== VERSION) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

// 捕获请求并返回缓存数据
self.addEventListener(
  'fetch',
  /**
   * @param {{request: Request}} event
   */
  function (event) {
    event.respondWith(
      caches.match(event.request).then(function (response) {
        if (response) {
          return response;
        }
        const request = event.request.clone();
        return fetch(request)
          .then((res) => {
            if (!res || res.status !== 200) {
              return res;
            }
            const responseToCache = res.clone();
            caches.open(VERSION).then(function (cache) {
              cache.put(requst, responseToCache);
            });
            return res;
          })
          .catch(() => {
            return fetch(event.request.url, { mode: 'no-cors' });
          });
      })
    );
  }
);

一些踩坑记录

  1. sw中的event.respondWith不存在后悔项, 我的意思是, 一旦调用了这个接口, 就要想办法返回一个内容. 不能在发现出错后继续走原有的请求
  2. request在捕获时还没有拿到cookies, 而sw本身是没有cookies缓存的, 也就是说如果服务端校验了cookies的话, 会导致本来正常请求可以获得结果的, 但使用了sw捕获之后反而出错了.
  3. 默认的img请求, 它的request设置默认是'no-cors'的, 这个参数的意义是即便我们捕获了返回, 也会发现res.data是null, 将这个res缓存下来下次返回, 所以必须要手动新建一个request并且设置为'cors', 但这时候也有可能出错, 本人当前的方法是直接fetch(event.request.url)并缓存. 所以在这里, 有的时候使用request.clone才能得到正确返回, 有的时候必须使用url才能得到正确返回, 这里面的区别就需要仔细区分测试才行.

跨域的缓存

  1. sw其实也支持跨域, 只需要服务端返回Access-Control-Allow-Origin: *, 就可以得到跨域的缓存.