【问题标题】:Service worker not caching assets on homepage without trailing slash服务工作者没有在没有斜杠的情况下在主页上缓存资产
【发布时间】:2021-07-16 14:56:53
【问题描述】:

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

我已将 Service Worker 允许的标头添加到应用程序的站点:

<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/,我可以看到缓存已更新所有文件。有没有办法让 Service Worker 下载主页的文件而不带斜线?

服务工作者代码:

(() => {
  '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' } });
  }
})();

【问题讨论】:

    标签: progressive-web-apps service-worker cachestorage


    【解决方案1】:

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

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

    Above text is point 7

    我在 activate 函数中添加了self.clients.claim(),它允许 service worker 立即控制注册页面,这使得一些惰性加载或在 service worker 之后加载的资产无需刷新即可缓存,但其余的仅在刷新后缓存

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多