ServiceWorker:没有 javascript 触发请求的 FetchEvent?
ServiceWorker: No FetchEvent for javascript triggered request?
我正在使用 Chrome 稳定版 46。
我有一个非常基本的网站。一个 button.onclick fetch('a')
和一个 <a>
打开 b
的标签。 url a
和 b
都不存在,我打算在 service worker 中捕获它们,只是 return a new Response()
.
如果我点击获取 a
的按钮,服务人员不参与,我收到 404 错误。
但是,如果我单击转到 b
的 link,服务人员将获取并 return 响应。
问题:为什么 service worker 没有为 fetch('a')
请求获取任何 FetchEvent?
查看下面的文件
HTML
<html>
<body>
<p><button onclick="fetch('a');">fetch a</button></p>
<p><a href="b">go to b</a></p>
<script src="js.js" defer></script>
</body>
</html>
js.js
navigator.serviceWorker.register('sw.js');
sw.js
self.onfetch = function(event) {
var request = event.request;
event.respondWith(
caches.match(request).then(function(response) {
return new Response('here is your onfetch response');
})
);
};
Service Worker 的 fetch
事件处理程序在您第一次加载页面时未被调用,因为 Service Worker 尚未 "claimed" 页面,这意味着它不在 Service Worker 的控制。默认情况下,当您第一次访问注册了 service worker 的站点时,service worker 的 install
(可能还有 activate
)事件处理程序将 运行,但 fetch
不会在 service worker 取得控制权之前不会被触发。下次您导航到服务工作者范围内的页面时,或者如果您重新加载当前页面时,就会发生这种情况。
您可以通过在 activate
事件处理程序中调用 self.clients.claim()
来覆盖此默认行为并让服务工作者在初始导航期间进行控制。
我还想指出,您示例中的 fetch
事件处理程序存在一些问题 — 如果您总是计划 returning,则没有理由调用 caches.match(request)
一个新的 Response
对象。更重要的是,您需要对 event.request.url
值进行某种检查,并且只有 return 新的 Response
如果它与您的 "special" URL 之一匹配,在您的情况下是 a
和 b
。现在的实现方式是,您的 fetch
处理程序将无条件地 return 虚拟 Response
,即使它是对您的主页 (index.html
) 的后续请求。这大概不是你想要的。
感谢 RawGit,我放了 gist together that modifies your service worker code to accomplish what I believe you're attempting. You can try out a live version。为了后代,这里是修改后的服务工作者代码:
self.addEventListener('install', event => {
// Bypass the waiting lifecycle stage,
// just in case there's an older version of this SW registration.
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', event => {
// Take control of all pages under this SW's scope immediately,
// instead of waiting for reload/navigation.
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', event => {
// In a real app, you'd use a more sophisticated URL check.
if (event.request.url.match(/a|b$/)) {
event.respondWith(new Response('here is your onfetch response'));
}
});
我正在使用 Chrome 稳定版 46。
我有一个非常基本的网站。一个 button.onclick fetch('a')
和一个 <a>
打开 b
的标签。 url a
和 b
都不存在,我打算在 service worker 中捕获它们,只是 return a new Response()
.
如果我点击获取 a
的按钮,服务人员不参与,我收到 404 错误。
但是,如果我单击转到 b
的 link,服务人员将获取并 return 响应。
问题:为什么 service worker 没有为 fetch('a')
请求获取任何 FetchEvent?
查看下面的文件
HTML
<html>
<body>
<p><button onclick="fetch('a');">fetch a</button></p>
<p><a href="b">go to b</a></p>
<script src="js.js" defer></script>
</body>
</html>
js.js
navigator.serviceWorker.register('sw.js');
sw.js
self.onfetch = function(event) {
var request = event.request;
event.respondWith(
caches.match(request).then(function(response) {
return new Response('here is your onfetch response');
})
);
};
Service Worker 的 fetch
事件处理程序在您第一次加载页面时未被调用,因为 Service Worker 尚未 "claimed" 页面,这意味着它不在 Service Worker 的控制。默认情况下,当您第一次访问注册了 service worker 的站点时,service worker 的 install
(可能还有 activate
)事件处理程序将 运行,但 fetch
不会在 service worker 取得控制权之前不会被触发。下次您导航到服务工作者范围内的页面时,或者如果您重新加载当前页面时,就会发生这种情况。
您可以通过在 activate
事件处理程序中调用 self.clients.claim()
来覆盖此默认行为并让服务工作者在初始导航期间进行控制。
我还想指出,您示例中的 fetch
事件处理程序存在一些问题 — 如果您总是计划 returning,则没有理由调用 caches.match(request)
一个新的 Response
对象。更重要的是,您需要对 event.request.url
值进行某种检查,并且只有 return 新的 Response
如果它与您的 "special" URL 之一匹配,在您的情况下是 a
和 b
。现在的实现方式是,您的 fetch
处理程序将无条件地 return 虚拟 Response
,即使它是对您的主页 (index.html
) 的后续请求。这大概不是你想要的。
感谢 RawGit,我放了 gist together that modifies your service worker code to accomplish what I believe you're attempting. You can try out a live version。为了后代,这里是修改后的服务工作者代码:
self.addEventListener('install', event => {
// Bypass the waiting lifecycle stage,
// just in case there's an older version of this SW registration.
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', event => {
// Take control of all pages under this SW's scope immediately,
// instead of waiting for reload/navigation.
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', event => {
// In a real app, you'd use a more sophisticated URL check.
if (event.request.url.match(/a|b$/)) {
event.respondWith(new Response('here is your onfetch response'));
}
});