我正在使用 Service Worker 为我的网站创建一个离线页面。
目前我正在将 offline.html
保存到缓存中,以便浏览器可以在没有内部连接时显示此文件。
在我的 service worker 的 fetch
事件中,我尝试加载 index.html
,如果失败(无互联网连接),我加载 offline.html
来自缓存。
但是,每当我在开发人员工具中检查离线模式并刷新页面时,index.html
仍然显示...
请求没有失败,看起来 index.html
正在被缓存,即使我没有指定它。
这是我的 index.html
的 HTML:
<!DOCTYPE html>
<html>
<head>
<title>Service Workers - Test</title>
</head>
<body>
<h1> Online page! </h1>
<h3> You are connected to the internet. </h3>
</body>
<script>
if ('serviceWorker' in navigator)
{
navigator.serviceWorker.register('service-worker.js');
}
</script>
</html>
这是我的 offline.html
的 HTML:
<!DOCTYPE html>
<html>
<head>
<title>You are Offline - Service Workers - Test</title>
</head>
<body>
<h1> Welcome to the Offline Page!</h1>
<h2> You are not connected to the internet but you can still do certain things offline. </h2>
</body>
</html>
这是我的 service-worker.js
的 javascript:
const PRECACHE = "version1"
const CACHED = ["offline.html"];
// Caches "offline.html" incase there is no internet
self.addEventListener('install', event => {
console.log("[Service Worker] Installed");
caches.delete(PRECACHE)
event.waitUntil (
caches.open(PRECACHE)
.then(cache => cache.addAll(CACHED))
.then( _ => self.skipWaiting())
);
});
// Clears any caches that do not match this version
self.addEventListener("activate", event => {
event.waitUntil (
caches.keys()
.then(keys => {
return Promise.all (
keys.filter(key => {
return !key.startsWith(PRECACHE);
})
.map(key => {
return caches.delete(key);
})
);
})
.then(() => {
console.log('[Service Worker] Cleared Old Cache');
})
);
});
this.addEventListener('fetch', function(event) {
if (event.request.method !== 'GET') return;
console.log("[Service Worker] Handling Request ");
// If the request to `index.html` works it shows it, but if it fails it shows the cached version of `offline.html`
// This isn't working because `fetch` doesn't fail when there is no internet for some reason...
event.respondWith (
fetch(event.request)
.then(response => {
console.log("[Service Worker] Served from NETWORK");
return response;
}, () => {
console.log("[Service Worker] Served from CACHE");
return catches.match(event.request.url + OFFLINE_URL);
})
);
});
我正在使用 python 的简单 http 服务器运行服务器,如下所示:
python -m SimpleHTTPServer
有谁知道为什么离线页面无法正常工作以及我该如何解决这个问题?
感谢您的帮助, 大卫
编辑:
这些图像显示 index.html
(本地主机)仍在没有互联网的情况下加载,这意味着它必须被缓存。
编辑 2:
我已经尝试将 no-cache
添加到 index.html
的提取中,但它仍然在提取 index.html
当我已离线检查。
fetch(event.request, {cache: "no-cache"}) ...
最佳答案
我想我们都忘记了从浏览器的 Angular 来看网络请求是如何工作的。
这里的问题是,当 service worker 拦截请求时,index.html
是从磁盘缓存中获取的。
浏览器 ===> Service Worker ===>获取事件
inside the fetch event, we have ,
- Check If there is network connectivity
- If there is, fetch from network and respond
- Else, fetch from cache and respond
现在,怎么样
If there is network connectivity, fetch from network work?
Service Worker OnFetch ===> 检查磁盘缓存 ===>什么都没有?在线获取
这里获取的页面是index.html
和 index.html
的 cache-control
header ,
不指定no-cache
因此脱机页面的整个问题没有显示。
解决方案
- 为
index.html
设置一个cache-control
header 限制值 - 在服务器端 或者,在fetch请求中添加headers达到效果
pragma:no-cache
缓存控制:无缓存
如何添加这些 header 以进行抓取?
显然,当涉及到 GET 时,fetch 和浏览器对请求正文有自己的保留
此外,如果您为获取请求重用 event.request
对象,并添加自定义 header ,则会发生奇怪和彻底的困惑。
困惑是由于 fetch
事件的 request.mode
属性导致的 Uncaught Exceptions
列表,它禁止您在获取时添加自定义 header 在 no-cors 或导航模式下。
我们的目标是:
识别浏览器确实离线,然后提供一个这样说明的页面
方法如下:
Check If you can fetch a dummy html page say
test-connectivity.html
under your origin, with a customcache: no-cache
header. If you can, proceed, else throw the offline page
self.addEventListener( 'fetch', ( event ) => {
let headers = new Headers();
headers.append( 'cache-control', 'no-cache' );
headers.append( 'pragma', 'no-cache' );
var req = new Request( 'test-connectivity.html', {
method: 'GET',
mode: 'same-origin',
headers: headers,
redirect: 'manual' // let browser handle redirects
} );
event.respondWith( fetch( req, {
cache: 'no-store'
} )
.then( function ( response ) {
return fetch( event.request )
} )
.catch( function ( err ) {
return new Response( '<div><h2>Uh oh that did not work</h2></div>', {
headers: {
'Content-type': 'text/html'
}
} )
} ) )
} );
{cache:'no-store'}
对象作为 fetch
的第二个参数,是一个不幸的NO-OP。只是行不通。
为了将来的情况,请保留它。从今天起,它真的是可选的。
如果可行,那么您不需要为 fetch
构建一个全新的 Request
对象
干杯!
The code piece that creates a new request is generously borrowed from @pirxpilot 's answer here
pastebin 上这个特定问题的离线 worker
关于Javascript - Service Worker 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45447325/