Service Worker:当服务器上的文件发生变化时如何更新缓存?
Service Worker: how to update the cache when files changed on the server?
您使用什么缓存策略?我阅读了 Offline Cookbook,最简单的策略是缓存静态内容并忽略 API 调用。
这个策略看起来是这样的:
- 检查请求是否已经在缓存中
- 如果不将请求、响应对添加到缓存
- Return 回应
如果服务器端文件已更改,如何更新缓存?目前客户端始终获取缓存结果。
这是我的缓存策略代码:
// 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。
那里使用的策略是:
- Gulp 正在生成带有校验和的 Service Worker 文件
- Service Worker 已注册(使用自己的校验和)
- 如果文件是 added/updated,则 SW 文件会更改
- 下次访问时,SW 检查其校验和是否不同,因此它会再次使用更新的文件注册自己
您可以通过后端以任何您想要的方式自动执行此流程:)
他在 this article
中描述得更好
这是我用来缓存的代码。它获取资源并缓存并提供它。
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:
When the user navigates to your site, the browser tries to redownload the script file that defined the service worker in the background. If there is even a byte's difference in the service worker file compared to what it currently has, it considers it 'new'.
因此,即使您只需要更改静态资源,您也必须更新您的服务工作者文件,以便注册一个新的服务工作者来更新缓存。 (您需要确保在 activate
处理程序中也删除任何以前的缓存。)@Karol Klepacki 的回答提出了一种自动化方法。
或者,您可以在 Service Worker 本身中实现逻辑,以定期检查缓存资源的更改并适当更新条目。
您使用什么缓存策略?我阅读了 Offline Cookbook,最简单的策略是缓存静态内容并忽略 API 调用。
这个策略看起来是这样的:
- 检查请求是否已经在缓存中
- 如果不将请求、响应对添加到缓存
- Return 回应
如果服务器端文件已更改,如何更新缓存?目前客户端始终获取缓存结果。
这是我的缓存策略代码:
// 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。
那里使用的策略是:
- Gulp 正在生成带有校验和的 Service Worker 文件
- Service Worker 已注册(使用自己的校验和)
- 如果文件是 added/updated,则 SW 文件会更改
- 下次访问时,SW 检查其校验和是否不同,因此它会再次使用更新的文件注册自己
您可以通过后端以任何您想要的方式自动执行此流程:)
他在 this article
中描述得更好这是我用来缓存的代码。它获取资源并缓存并提供它。
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:
When the user navigates to your site, the browser tries to redownload the script file that defined the service worker in the background. If there is even a byte's difference in the service worker file compared to what it currently has, it considers it 'new'.
因此,即使您只需要更改静态资源,您也必须更新您的服务工作者文件,以便注册一个新的服务工作者来更新缓存。 (您需要确保在 activate
处理程序中也删除任何以前的缓存。)@Karol Klepacki 的回答提出了一种自动化方法。
或者,您可以在 Service Worker 本身中实现逻辑,以定期检查缓存资源的更改并适当更新条目。