Service Worker 无法在节点 js 服务器的离线模式下工作

Posted

技术标签:

【中文标题】Service Worker 无法在节点 js 服务器的离线模式下工作【英文标题】:Service Worker not working in Offline mode with node js server 【发布时间】:2018-02-05 01:20:06 【问题描述】: 我正在尝试使用离线优先策略构建 PWA。 源文件的服务器是 NodeJS 服务器。 我目前正在 localhost 节点服务器上对此进行测试(不确定它是否有影响?)。 Service Worker + 缓存看起来不错,但在离线模式下我只能看到 Chrome 离线页面

让我们深入了解一下:

提供的页面(通过http://localhost:8080/place/test url)有一些客户端JS,我在其中注册了一个Service Worker:

client.js

    if ('serviceWorker' in navigator) 
        navigator.serviceWorker
                 .register(rootPath+'/js/service-worker.js')
                 .then(function()  console.log('Service Worker Registered'); );
    

service-worker.js(基于 Google PWA 教程)

var cacheName = 'myCacheVersion';
var filesToCache = [
    '../',
    '../place/test',
    '../js/client.js',
    '../js/service-worker.js',
    "../css/style.css"
];


self.addEventListener('install', function(e) 
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) 
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    )
  );
);

self.addEventListener('activate', function(e) 
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    caches.keys().then(function(keyList) 
      return Promise.all(keyList.map(function(key) 
        if (key !== cacheName) 
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        
      ));
    )
  );
  return self.clients.claim();
);

self.addEventListener('fetch', function(e) 
  console.log('[ServiceWorker] Fetch', e.request.url);
  e.respondWith(
    caches.match(e.request).then(function(response) 
      return response || fetch(e.request);
    )
  );
);

在开发工具控制台中,一切似乎都很好:

软件已注册 缓存包含我想要缓存的元素

但是当我选中 离线模式复选框 并刷新我的页面网址:http://localhost:8080/place/test 时,我只得到 Google Chrome 离线网页

=> 我在那里缺少什么?(它与 nodeJs 有关系吗?与 localhost 环境有关?与我的实现有关?)

我一直在努力解决这个问题......

我已经检查了“应用程序”选项卡,我的服务人员显示为已激活并正在运行。

注意:如果在这里找到了类似的问题,但在那里没有满意的答案:Service worker not run in offline mode using nodejs server

【问题讨论】:

你说的SW注册了; (如对您链接到的其他问题的评论)它是否显示在“应用程序”选项卡中? 是的,它显示为“已激活并正在运行” 【参考方案1】:

基本上,这与此处回答的问题相同:Service worker is caching files but fetch event is never fired

如果您查看控制台,您会发现虽然安装、激活、缓存和注册都发生了,但“获取”却不会。这是因为您将 Service Worker 定位在 js 下,因此出于安全原因,Chrome (etc) 不会将其用于除同一目录或以下目录中的任何 URL。

如果您将client.jsservice-worker.js 放在同一级别而不是js 子目录中,则它们都将开始工作。这将需要更新文件的内容,我将在下面显示以供参考。

一个小小的警告:我愚蠢地在 Windows 机器上使用 IIS 来处理这个问题,而在它和 Chrome 之间,他们死死地抓住了缓存的 html 文件,其中包含过时的 JS 文件位置。我不得不将它们复制到一个子目录中,制作新的 URL,以测试解决方案。

index.html:

<head>
<script src="client.js"></script>
</head>
<body>
<a href="cachetest.html">link to ct</a>
</body>

cachetest.html:

<head>
<script src="client.js"></script>
</head>
<body>cachetest</body>

client.js:

if ('serviceWorker' in navigator) 
    navigator.serviceWorker
             .register('service-worker.js')
             .then(function()  console.log('Service Worker Registered'); );

serviceworker.js:

var cacheName = 'myCacheVersion';
var filesToCache = [
    '',
    'cachetest.html',
    'client.js',
    'service-worker.js',
//    "css/style.css"
];


self.addEventListener('install', function(e) 
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) 
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    )
  );
);

self.addEventListener('activate', function(e) 
  console.log('[ServiceWorker] Activate');
  e.waitUntil(
    caches.keys().then(function(keyList) 
      return Promise.all(keyList.map(function(key) 
        if (key !== cacheName) 
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        
      ));
    )
  );
  return self.clients.claim();
);

self.addEventListener('fetch', function(e) 
  console.log('[ServiceWorker] Fetch', e.request.url);
  e.respondWith(
    caches.match(e.request).then(function(response) 
      return response || fetch(e.request);
    )
  );
);

【讨论】:

你成功了!我只需要将我的 service-worker.js 移动到我的根目录,并对文件路径+缓存文件列表路径进行一些更改即可工作...稍后注意:记住服务-worker 只能访问其级别或以下...非常感谢! (我赞成你的答案,但在这里是新的,它还没有显示......) 谢谢!祝你的其他东西好运。我要看看这是否也是另一个问题的答案。 或者,你可以! :-) 我还将我的服务工作者添加到了我的应用程序 /service-worker.js 的根目录中,一切都开始工作了。谢谢! 谢谢,放置注册软件和实际的服务人员解决问题。

以上是关于Service Worker 无法在节点 js 服务器的离线模式下工作的主要内容,如果未能解决你的问题,请参考以下文章

在 django 项目中将 service worker 和 manifest 放在哪里?

Rails 对 service-worker.js 的未知调用

web worker 与 service worker

@vue/cli-plugin-pwa 没有创建 service-worker.js

与 Angular.js 控制器通信 service-worker

学习笔记create-react-app 自定义Service Worker