Javascript - Service Worker 无法正常工作

标签 javascript python html caching service-worker

我正在使用 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(本地主机)仍在没有互联网的情况下加载,这意味着它必须被缓存。

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"}) ...

最佳答案

我想我们都忘记了从浏览器的 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.htmlcache-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 custom cache: 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

https://pastebin.com/sNCutAw7

关于Javascript - Service Worker 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45447325/

相关文章:

python - 如何通过 SSH 为不同网络上的设备设置 python、telnet 代理?

python - multiprocessing.connection.Client 连接重试时间

python - 属性错误: 'Action' object has no attribute 'text1'

javascript - 单击导航菜单下拉菜单关闭

javascript - 错误 document.geElementById ('id' ).style.width

javascript - 在输入类型 = 文件中没有选择文件的情况下提交表单超时

c# - 滚动时修复 gridview 标题

javascript - 清除并添加新类别?

javascript - 两个 td 标签不能并排滑动

html - HTML 中的 TAB 菜单