[英]Javascript - Service Workers not working correctly
I am using service workers to create an offline page for my website. 我正在使用服务人员为我的网站创建一个脱机页面。
At the moment I am saving offline.html
into cache so that the browser can show this file if there is no interent connection. 目前,我将
offline.html
保存到缓存中,以便浏览器可以在没有内部连接的情况下显示此文件。
In the fetch
event of my service worker I attempt to load index.html
, and if this fails (no internet connection) I load offline.html
from cache. 在服务工作者的
fetch
事件中,我尝试加载index.html
,如果失败(没有互联网连接),我将从缓存加载offline.html
。
However, whenever I check offline mode in developer tools and refresh the page index.html
still shows... 但是,每当我在开发人员工具中检查离线模式并刷新页面时,
index.html
仍显示...
The request isn't failing, and it looks like index.html
is being cached even though I didn't specify it to be. 该请求没有失败,即使我未指定为
index.html
,它也似乎正在缓存。
Here is my HTML for 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>
Here is my HTML for offline.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>
Here is my javascript for service-worker.js
: 这是我的
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);
})
);
});
I am running a server using python's simple http server like so: 我正在使用python的简单http服务器运行服务器,如下所示:
python -m SimpleHTTPServer
Does anyone know why the offline page isn't working and how I can fix this? 有谁知道为什么离线页面无法正常工作以及如何解决?
Thanks for the help, David 谢谢你的帮助,大卫
EDIT: 编辑:
These images are showing that index.html
(localhost) is still loading without internet which means it must be cached. 这些图像显示
index.html
(localhost)仍在没有互联网的情况下加载,这意味着必须对其进行缓存。
Edit 2: 编辑2:
I've tried to add no-cache
to the fetch of index.html
and it still is fetching index.html
when I have offline checked. 我试图将
no-cache
添加到index.html
的获取中,但当我进行离线检查时,它仍在获取index.html
。
fetch(event.request, {cache: "no-cache"}) ...
David, you have two errors in one line. 大卫,您在一行中有两个错误。
Your line 你的线
return catches.match(event.request.url + OFFLINE_URL);
should be 应该
return caches.match('offline.html');
It's catches
and you haven't defined OFFLINE_URL
and you don't need event request url catches
,您还没有定义OFFLINE_URL
,也不需要事件请求url
I tried your code and I got the same result as you in the dev tools network tab. 我尝试了您的代码,并在“开发工具”网络标签中获得了与您相同的结果。 The network tab says it loaded the index.html from service-worker, but actually the service-worker returns the cached Offline Page as expected!
网络选项卡说它从service-worker加载了index.html,但是实际上service-worker返回了缓存的脱机页面!
I think we have all forgotten how the network request works from a browser's point of view. 我认为我们都忘记了从浏览器的角度来看网络请求是如何工作的。
The issue here is, index.html
is served from the disk cache when the service worker intercepts requests. 这里的问题是,当服务工作者拦截请求时,将从磁盘缓存中提供
index.html
。 browser ===> Service Worker ===> fetch event 浏览器 ===> 服务工作者 ===> 获取事件
inside the fetch event, we have ,
在fetch事件中,我们有
- Check If there is network connectivity
检查是否存在网络连接
- If there is, fetch from network and respond
如果存在,请从网络获取并响应
- Else, fetch from cache and respond
否则,从缓存中获取并响应
Now, how does 现在,如何
If there is network connectivity, fetch from network work?
如果存在网络连接,是否可以从网络工作中获取?
Service Worker OnFetch ===> Check in Disk Cache ===> Nothing? Service Worker OnFetch ===> 检入磁盘缓存 ===> 什么都没有? Fetch Online
在线获取
The page being fetched here, is index.html
此处获取的页面是
index.html
and the cache-control
headers for index.html
, 以及
index.html
的cache-control
标头,
Do Not Specify a no-cache
不指定
no-cache
Hence the whole issue of the offline page not showing up. 因此,脱机页面的整个问题没有显示出来。
cache-control
header with limiting values for index.html
- On the server side index.html
设置具有限制值的cache-control
标头-在服务器端 Or, add headers in the fetch request to the effect 或者,在获取请求中添加标题以达到效果
pragma:no-cache
cache-control:no-cache
Apparently, fetch and the browser have their own reservations about the request body when it comes to a GET 显然,当涉及到GET时,提取和浏览器对请求正文有自己的保留
Also, weirdness and utter chaos happens If you reuse the event.request
object, for a fetch request, and add custom headers. 同样,如果您重复使用
event.request
对象以获取请求并添加自定义标头,则会发生怪异和完全混乱。 The chaos is a list of Uncaught Exceptions
due to the fetch
event's request.mode
attribute , which bars you from adding custom headers to a fetch when under a no-cors or a navigate mode. 由于
fetch
事件的request.mode
属性,混乱是Uncaught Exceptions
的列表,该列表禁止您在无条件或导航模式下将自定义标头添加到fetch。
Our goal is to : 我们的目标是:
Identify that the browser is truly offline and then serve a page that says so 确定浏览器确实处于离线状态 ,然后提供一个如下所示的页面
Here's How: 这是如何做:
Check If you can fetch a dummy html page say
test-connectivity.html
under your origin, with a customcache: no-cache
header.检查是否可以获取虚拟的html页面,在源下面说
test-connectivity.html
,并带有一个自定义cache: no-cache
标头。 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'
}
} )
} ) )
} );
The {cache:'no-store'}
object as the second parameter to fetch
, is an unfortunate NO-OP . {cache:'no-store'}
对象是要fetch
的第二个参数,它是不幸的NO-OP 。 Just doesn't work. 只是不起作用。 Just keep it for the sake of a future scenario.
只是保留它以便将来使用。 It is really optional as of today.
到目前为止,它确实是可选的。
If that worked, then you do not need to build a whole new Request
object for fetch
如果可行,那么您无需构建一个全新的
Request
对象即可进行fetch
cheers! 干杯!
The code piece that creates a new request is generously borrowed from @pirxpilot 's answer here
创建一个新的请求的代码片慷慨从@pirxpilot的回答借来这里
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.