服务人员从磁盘缓存中缓存资源

时间:2019-09-07 14:33:14

标签: service-worker

我正在创建一个需要脱机支持和更新的Web应用程序。当我更新应用程序时,新的服务工作者开始从磁盘缓存中缓存文件,并且不更新应用程序。这将导致新的缓存获取旧文件。 Screenshot of chrome network debbuging

const STATICCACHE = 'v9';
const DYNCACHE = 'dv2';
//v9
const assets = [
// All my assets
];

// install
self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(STATICCACHE).then(cache => {
            console.log("caching assets");
            cache.addAll(assets);
        })
    );

});

// activate event
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(keys => {
            return Promise.all(keys
                .filter(key => key !== STATICCACHE && key !== DYNCACHE)
                .map(key => caches.delete(key))
            )
        })
    )
});

//fetch event
self.addEventListener('fetch', event => {
    if (event.request.url.indexOf('firestore.googleapis.com') === -1) {
        event.respondWith(
            caches.match(event.request).then(cacheRes => {
                return cacheRes || fetch(event.request).then(fetchRes => {
                    return caches.open(DYNCACHE).then(cache => {
                        cache.put(event.request.url, fetchRes.clone());
                        return fetchRes;
                    })
                });
            })
        );
    }
});

在适用于Android的chrome浏览器和iOS上的Safari浏览器中,该功能也无法正常工作。

感谢您的帮助

1 个答案:

答案 0 :(得分:0)

之所以会发生这种情况,是因为资产的名称在更新时不会更改,例如。无论文件内容如何,​​app.js始终都是app.js。从浏览器的角度来看,文件没有更改。

您可以通过以下两种主要方法进行处理:

  1. 确保您的服务器对所有静态资产使用正确的HTTP标头,例如。 ETag或缓存:过期验证等。通过这种方式,即使资产名称没有更改,您也可以强制浏览器检查服务器的新版本。

  2. 任何方式更改文件时,始终更改它们的名称。

第二个选项是大多数人在开发Web应用程序时使用的内容。通常,工具,JS捆绑器等确保文件名更改。文件名通常分为两部分,包括文件内容的哈希值:例如app.8927349789adf8.jsstyles.329789dfs89sigjg.css。当然,您不想手动执行此操作,而是使用Webpack或Parcel等之类的方法。

您还可以使用一些解决方法,例如使浏览器请求。 app.js?XXXXXX,其中XXXXX是当前时间或类似的时间。此外,如果您要合并某些Service Worker库(如Workbox),则即使名称保持不变,它也支持跟踪文件内容的更改。基本上,Workbox会计算文件的哈希值,然后使用查询参数技巧将其缓存。 styles.css?_HASH_OF_THE_FILE。您也可以将这种技巧结合到手写的SW文件中-当缓存名称更改时,只需从服务器请求文件,然后在所有请求中附加?current_time之类的内容即可。这将迫使浏览器执行网络请求。