我刚刚尝试实现服务工作者在静态站点上缓存一些JSON文件和其他资产(在localhost chrome版本47.0.2526.73(64位)上运行)。使用cache.addAll()我已将文件添加到缓存中,当我打开chrome中的资源选项卡,然后单击缓存存储时,将列出所有文件。
我遇到的问题是我的服务工作者被列为"已激活"和"跑步"在chrome:// service-worker-internals中,我无法确定该worker是否实际上是在拦截请求并提供缓存文件。我添加了事件监听器,即使我在服务工作者开发工具实例中控制日志事件,它也永远不会到达断点:
/tweeting
基本上我正在按照HTML5中描述的方式运行服务工作者介绍,但我很确定我的资产不是从缓存中提供的。我已经注意到,服务工作人员提供的资产在尺寸列中的devtools的网络标签中通过指示来自服务工作者的信息而被注明。
看起来好像我的代码与示例没什么不同,但是由于某种原因它并没有达到fetch事件。我的代码要点:https://gist.github.com/srhise/c2099b347f68b958884d
答案 0 :(得分:60)
在看完你的要点和问题后,我认为你的问题在于范围界定。
根据我对服务工作者的判断(至少使用静态文件),服务工作者只有最大的目录范围。也就是说,它无法加载文件/请求/响应从其结构或其上方的位置拉出,仅在下方。
例如,/ js /service-worker.js只能加载/ js / {dirName} /中的文件。
因此,如果您将服务工作者的位置更改为Web项目的根目录,则应触发fetch事件,并且您的资产应从缓存加载。
类似于/service-worker.js,它应该能够访问/ json目录,因为它比service-worker.js文件更深。
这里将在"注册A服务工作者"中进一步解释。部分。 https://developers.google.com/web/fundamentals/getting-started/primers/service-workers
答案 1 :(得分:27)
我很长时间以来一直在努力,我认为与此事有关的文件严重缺乏。根据我的经验,有一个非常重要的区别:
如果服务工作者在从访问 URL的范围之内或之上,则只能拦截获取事件。
例如,我的sw.js文件位于/static/sw.js
。在/
访问我的站点根目录并尝试拦截f /static/js/common.js
中的js文件的fetch文件时,即使我的服务工作者的范围是/static/
,也没有拦截获取事件。 js文件位于/static/js/
。
将sw.js文件移至顶级作用域/sw.js
后,抓取事件全部被截获。这是因为我使用浏览器/
访问的页面范围与我的sw.js文件/
的范围相同。
如果这样可以为人们解决问题,或者我不正确,请告诉我们。
答案 2 :(得分:3)
HTML5Rocks文章中的确切代码是
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have 2 stream.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
我能看到的最重要的事情是你没有从抓取中克隆request
,你需要克隆它,因为它被读取两次,一次用于访问网络时(在{{ 1}})和一次用作缓存的密钥。
答案 3 :(得分:2)
如果您没有看到标记from service worker
,那么服务工作人员的页面不是受控(您可以通过检查客户端页面中的navigator.serviceWorker.controller
进行检查) 。页面的默认行为是在SW激活后下次访问时控制,因此您有两个选项:
self.skipWaiting()
和self.clients.claim()
方法强制服务工作者尽快控制客户端。查看Service Worker Cookbook,其中包含JSON cache recipe。
使用控件修复问题后,您需要修复处理程序。我想您要应用 cache-first 的策略。如果不在缓存中,则转到网络并填充缓存。要做到这一点:
self.onfetch = function (event) {
var req = event.request;
return event.respondWith(function cacheFirst() {
// Open your cache.
return self.caches.open('v1').then(function (cache) {
// Check if the request is in there.
return cache.match(req).then(function (res) {
// If not match, there is no rejection but an undefined response.
if (!res) {
// Go to network.
return fetch(req.clone()).then(function (res) {
// Put in cache and return the network response.
return cache.put(req, res.clone()).then(function () {
return res;
});
});
}
return res;
});
});
});
}
答案 4 :(得分:0)
当我将sw.js与Django Framework一起使用时,我遇到了同样的问题。 Here我找到了解决方法。