0

我正在尝试将服务工作者添加到在应用程序下运行的我们网站的一部分,除了主页没有尾部斜杠之外,它都可以正常工作 - 它将缓存页面但不会下载任何资产,除非我添加斜杠到url(我不能这样做,因为实时环境将其删除)

我已将服务工作者允许的标头添加到应用程序的站点:

<add name="Service-Worker-Allowed" value="/app-name" />

并更改范围以允许无斜杠 url:

// APP_NAME is global for app-name
navigator
  .serviceWorker
  .register(`/${APP_NAME}/service-worker.js`, { scope: `/${APP_NAME}` });

这很有效,因为我可以浏览到http://localhost/app-name离线,但它没有任何 css、js 或图像。

如果我浏览到http://localhost/app-name/我可以看到缓存已更新所有文件。有没有办法让服务人员在没有斜杠的情况下下载主页的文件?

服务工作者代码:

(() => {
  'use strict';

  const APP_NAME = 'app-name'; // define this as not compiled with webpack so no global
  const version = 1;
  const cacheName = `${APP_NAME}-cache`
  const cacheNameWithVersion = `${cacheName}-${version}`
  const offlineUrl = `/${APP_NAME}/offline`;
  const urlsToCache = [
    `/${APP_NAME}`,
    offlineUrl,
  ];
  const urlsToIgnore = [
    'google-analytics.com',
    'googletagmanager.com',
  ];

  self.addEventListener('install', event => {
    event.waitUntil(
      caches.open(cacheNameWithVersion)
        .then(cache => {
          return cache.addAll(urlsToCache);
        })
        // Force the waiting service worker to become the active service worker.
        .then(self.skipWaiting())
    );
  });

  self.addEventListener('activate', event => {
    event.waitUntil(
      caches.keys()
        .then(keys => {
          // Remove caches whose name is no longer valid
          return Promise.all(keys
            .filter(key => {
              return key.indexOf(cacheName) === 0 && key.indexOf(cacheNameWithVersion) === -1;
            })
            .map(key => {
              return caches.delete(key);
            })
          );
        })
    );
  });

  self.addEventListener('fetch', event => {
    // don't load assets from these urls
    for (let i = 0; i < urlsToIgnore.length; i++) {
      if (event.request.url.indexOf(urlsToIgnore[i]) > -1) {
        return;
      }
    }

    if (event.request.method !== 'GET') {
      // Always fetch non-GET requests from the network
      event.respondWith(
        fetch(event.request)
          .catch(() => {
            return caches.match(offlineUrl);
          })
      );

      return;
    }

    // Only fetch non-GET requests offline
    if (event.request.url.match(/\.(jpe?g|png|gif|svg)$/)) {
      // handle images or show offline svg if image isn't cached
      event.respondWith(
        caches.match(event.request)
          .then(response => {
            return response || fetch(event.request)
              .then(response => {
                addToCache(event.request, response);
                return response || serveOfflineImage();
              })
              .catch(() => {
                return serveOfflineImage();
              });
          })
      );
    } else if (event.request.mode === 'navigate' || event.request.method === 'GET') {
      // handle pages and assets like js and css
      event.respondWith(
        fetch(event.request)
          .then(response => {
            // Stash a copy of this page in the cache
            addToCache(event.request, response);
            return response;
          })
          .catch(() => {
            return caches.match(event.request)
              .then(response => {
                return response || caches.match(offlineUrl);
              });
          })
      );
    }
  });

  function addToCache(request, response) {
    if (!response.ok && response.type !== 'opaque')
      return;

    const copy = response.clone();
    caches.open(cacheNameWithVersion)
      .then(cache => {
        if (!/^https?:$/i.test(new URL(request.url).protocol)) return;
        cache.put(request, copy);
      });
  }

  function serveOfflineImage() {
    return new Response('<svg role="img" aria-labelledby="offline-title" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" class="object-fit"><title id="offline-title">Offline</title><g fill="none" fill-rule="evenodd"><path fill="#D8D8D8" d="M0 0h400v300H0z"/><text fill="#9B9B9B" font-family="Roboto,Arial,sans-serif" font-size="72" font-weight="bold"><tspan x="93" y="172">offline</tspan></text></g></svg>', { headers: { 'Content-Type': 'image/svg+xml' } });
  }
})();
4

1 回答 1

2

看起来您总是需要刷新注册服务工作者的页面才能下载该页面上的资产:

Service Worker 现在将控制页面,但只控制那些在 register() 成功后打开的页面。即,文档在有或没有 Service Worker 的情况下开始生命,并在其生命周期内维护它。因此,必须重新加载文档才能实际控制。

上面的文字是第 7 点

我已经添加self.clients.claim()了激活功能,它允许服务工作者立即控制注册页面,这允许一些在服务工作者之后延迟加载或加载的资产无需刷新即可被缓存,但其余的仅被缓存刷新后

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys()
    .then(keys => {
      // Remove caches whose name is no longer valid
      return Promise.all(keys
        .filter(key => {
          return key.indexOf(cacheName) === 0 && key.indexOf(cacheNameWithVersion) === -1;
        })
        .map(key => {
          return caches.delete(key);
        })
      );
    })
    // Retrieve assets on page that registered service worker
    .then(self.clients.claim())
  );
});
于 2021-04-22T12:22:06.557 回答