Javascript - 服务工作者无法正常工作

时间:2017-08-01 20:41:34

标签: javascript python html caching service-worker

我正在使用服务工作者为我的网站创建一个离线页面。

目前我正在将offline.html保存到缓存中,以便浏览器可以在没有互联网连接的情况下显示此文件。

在我的服务工作者的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(localhost)仍然在没有互联网的情况下加载,这意味着它必须被缓存。

Offline checkbox is ticked

localhost status:200 (from ServiceWorker) | service-worker.js status:failed

编辑2:

我已尝试将no-cache添加到index.html的抓取中,并且在我离线检查时仍然提取index.html

fetch(event.request, {cache: "no-cache"}) ...

3 个答案:

答案 0 :(得分:2)

大卫,你在一行中有两个错误。

你的行

return catches.match(event.request.url + OFFLINE_URL);

应该是

return caches.match('offline.html');

它是catches,您尚未定义OFFLINE_URL而且您不需要事件请求网址

答案 1 :(得分:2)

我尝试了您的代码,我在开发工具网络标签中得到了与您相同的结果。网络选项卡显示它从service-worker加载了index.html,但实际上service-worker按预期返回缓存的脱机页面!

Offline Page is shown

答案 2 :(得分:2)

我认为从浏览器的角度来看,我们都忘记了网络请求是如何工作的。

这里的问题是,当服务工作者拦截请求时,index.html从磁盘缓存提供。 浏览器 ===&gt; 服务工作者 ===&gt; 获取活动

  

在fetch事件中,我们有,

     
      
  • 检查是否存在网络连接      
        
    • 如果有,请从网络获取并回复
    •   
    • 否则,从缓存中获取并回复
    •   
  •   

现在,怎么做

  

如果有网络连接,请从网络工作中获取?

服务工作者OnFetch ===&gt; 签入磁盘缓存 ===&gt; 什么都没有?在线获取

此处提取的页面为index.html

以及cache-control的{​​{1}}标头,

指定index.html

因此,离线页面的整个问题都没有显示出来。

解决方案

  • 设置no-cache标头,其中包含cache-control的限制值 - 在服务器端
  • 或者,将获取请求中的标头添加到效果

    • index.html
    • pragma:no-cache

如何添加这些标题以获取?

显然,获取和浏览器在获取GET时对请求正文有自己的保留

此外,如果您重复使用cache-control:no-cache对象,获取提取请求并添加自定义标头,则会出现奇怪和彻头彻尾的混乱。 由于event.request事件的Uncaught Exceptions属性,混乱是fetch的列表,这禁止您在无人驾驶或导航模式下将自定义标头添加到抓取中。

我们的目标是:

确定浏览器真正离线,然后提供一个说明的页面

以下是如何:

  

检查您是否可以使用自定义request.mode标头获取您的来源下的虚拟html网页test-connectivity.html。如果可以,请继续,否则抛出离线页面

cache: no-cache

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'}的第二个参数,是一个不幸的 NO-OP 。只是不起作用。 只是为了未来的情况而保留它。截至今天,真的可选。

如果有效,那么您不需要为fetch

构建一个全新的Request对象

喝彩!

  

创建新请求的代码片段是慷慨借来的   @pirxpilot的回答here

关于pastebin

的特定问题的离线工作者

https://pastebin.com/sNCutAw7