Service Worker:当服务器上的文件发生变化时,如何更新缓存

Service Worker: how to update the cache when files changed on the server?

本文关键字:何更新 缓存 更新 变化 Worker 服务器 文件 Service      更新时间:2023-09-26

您使用什么缓存策略?我读了离线烹饪书,最简单的策略是缓存静态内容,并忽略API调用。

这个策略看起来像这样:

  1. 检查请求是否已经在缓存中
  2. 如果不添加请求,响应对缓存
  3. <
  4. 返回响应/gh>

如何更新缓存,如果在服务器端文件已更改?目前客户端总是得到缓存的结果。

下面是我的缓存策略代码:

// You will need this polyfill, at least on Chrome 41 and older.
importScripts("serviceworker-cache-polyfill.js");
var VERSION = 1;
var CACHES = {
    common: "common-cache" + VERSION
};
// an array of file locations we want to cache
var filesToCache = [
    "font-cache.html",
    "script.js",
];
var neededFiles = [
    "index.html"
];
var errorResponse = function() {
    return new Response([
            "<h2>Failed to get file</h2>",
            "<p>Could not retrive response from cache</p>"
        ].join("'n"),
        500
    );
};
var networkFetch = function(request) {
    return fetch(request).then(function(response) {
        caches.open(CACHES["common"]).then(function(cache) {
            return cache.put(request, response);
        });
    }).catch(function() {
        console.error("Network fetch failed");
        return errorResponse();
    });
}
this.addEventListener("install", function(evt) {
    evt.waitUntil(
        caches.open(CACHES["common"]).then(function(cache) {
            // Cache before
            cache.addAll(filesToCache);
            return cache.addAll(neededFiles);
        })
    );
});
this.addEventListener("activate", function(event) {
    var expectedCacheNames = Object.keys(CACHES).map(function(key) {
        return CACHES[key];
    });
    console.log("Activate the worker");
    // Active worker won"t be treated as activated until promise resolves successfully.
    event.waitUntil(
        caches.keys().then(function(cacheNames) {
            return Promise.all(
                cacheNames.map(function(cacheName) {
                    if (expectedCacheNames.indexOf() ===
                        -1) {
                        console.log(
                            "Deleting out of date cache:",
                            cacheName);
                        return caches.delete(cacheName);
                    }
                })
            );
        })
    );
});
self.addEventListener("fetch", function(event) {
    console.log("Handling fetch event for", event.request.url);
    event.respondWith(
        // Opens Cache objects
        caches.open(CACHES["common"]).then(function(cache) {
            return cache.match(event.request).then(function(
                response) {
                if (response) {
                    console.log("Found response in cache", response);
                    return response;
                } else {
                    return networkFetch(event.request);
                }
            }).catch(function(error) {
                // Handles exceptions that arise from match() or fetch().
                console.error(
                    "  Error in fetch handler:",
                    error);
                return errorResponse();
            });
        })
    );
});

您可能熟悉Jeff Posnick的解决方案- sw-precache。
这里使用的策略是:

  1. Gulp生成带有校验和的Service Worker文件
  2. Service Worker已注册(带有自己的校验和)
  3. 如果文件被添加/更新,SW文件更改
  4. 在下次访问时,SW检查其校验和是否不同,因此它再次用更新的文件注册自己

你可以用任何你想要的方式自动化这个流:)

他在这篇文章中描述得更好

这是我用来缓存的代码。它获取资源,缓存并提供服务。

this.addEventListener("fetch", function(event) {
  event.respondWith(
    fetch(event.request).then(function(response) {
      return caches.open("1").then(function(cache) {
        return cache.put(event.request, response.clone()).then(function() {
          return response
        })
      })
    }).catch(function() {
      return caches.match(event.request)
    })
  )
})

你必须修改Service Worker文件。根据Introduction to Service Worker:

当用户导航到你的站点时,浏览器会尝试在后台重新下载定义service worker的脚本文件。如果service worker文件中有一个字节的差异,它就会认为它是'new'。

所以即使你只需要改变静态资源,你也必须更新你的service worker文件,以便注册一个新的service worker来更新缓存。(你要确保在你的activate处理程序中删除任何以前的缓存)@Karol Klepacki的回答建议了一种自动化的方法。

或者,你可以在service worker本身中实现逻辑,定期检查缓存的资源是否有变化,并适当地更新条目。