Caching Fetch在服务工作者中返回200,即使处于脱机状态

Caching Fetch在服务工作者中返回200,即使处于脱机状态,caching,fetch,service-worker,progressive-web-apps,offlineapps,Caching,Fetch,Service Worker,Progressive Web Apps,Offlineapps,我希望我的Angularjs(1.x)应用程序有一个离线版本作为备用,以防没有网络或互联网服务 我需要服务工作者的获取事件侦听器,尝试从网络获取主页(当request.mode=='navigate'时),如果失败,则返回缓存版本 出于某种原因,即使我已断开wifi连接或在“飞行模式”下运行,获取始终返回状态码200 OK。但如果我打开Chrome的DevTools“网络>离线”模式,它确实可以工作 …我试过的: 我曾尝试使用“navigator.onLine”功能检测脱机模式,但不可靠 也试图

我希望我的Angularjs(1.x)应用程序有一个离线版本作为备用,以防没有网络或互联网服务

我需要服务工作者的获取事件侦听器,尝试从网络获取主页(当request.mode=='navigate'时),如果失败,则返回缓存版本

出于某种原因,即使我已断开wifi连接或在“飞行模式”下运行,获取始终返回状态码200 OK。但如果我打开Chrome的DevTools“网络>离线”模式,它确实可以工作

…我试过的: 我曾尝试使用“navigator.onLine”功能检测脱机模式,但不可靠

也试图清除缓存,但什么也没有。。仍然返回原始的“联机”html文档

还尝试将“缓存控制:无存储,无缓存”标头传递给获取,结果相同

self.addEventListener('fetch', function (event) {
  if (event.request.mode === 'navigate') {    
    event.respondWith(homeNetworkThenCache(event.request));
  } 
});

function homeNetworkThenCache(request){
  return fetch(request)
          .then(e => e)
          .catch(() => caches.match(offlineHomepageUrl));
}

预期行为: 如果没有internet连接,我希望fetch进入“catch”块,但它总是进入“.then(e=>e)”


…有什么想法吗?

如果您正在寻找一个只实现离线回退页面的示例服务人员,您可以这样做,它还将执行诸如启用导航预加载(如果支持)之类的操作:


您是否在HTML响应上设置了
Cache-Conrtol
标题?听起来您可能最终会从浏览器的“正常”HTTP缓存中读取这些响应。该请求是在您输入url时由浏览器发出的。。我在响应上没有看到任何“缓存控制”标题。请求将“缓存控制:最大年龄=0”发送到
事件中,而不是将
请求作为参数传递到
家庭网络缓存()
?这是你的真实代码还是你刚刚解释的?谢谢杰夫。。我已经添加了event.request参数,这是一个简化版本,不是真正的代码。谢谢Jeff的努力!非常感谢。。我尝试过“navigationPreload”功能,我不知道。然而,我还不能解决这个问题。我几乎可以肯定网络调用返回的是http缓存版本,正如您前面提到的。但是我不知道如何绕过它,因为原始请求也来自浏览器本身(无法在那里设置无缓存头)
cache Control
头可以在请求或响应上设置。(语义不同。)当浏览器发出请求时,您可以控制服务器的响应,您可以在该响应上设置
缓存控制:no Cache
const OFFLINE_VERSION = 1;
const CACHE_NAME = 'offline';
// Customize this with a different URL if needed.
const OFFLINE_URL = 'offline.html';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(CACHE_NAME);
    // Setting {cache: 'reload'} in the new request will ensure that the response
    // isn't fulfilled from the HTTP cache; i.e., it will be from the network.
    await cache.add(new Request(OFFLINE_URL, {cache: 'reload'}));
  })());
});

self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    // Enable navigation preload if it's supported.
    // See https://developers.google.com/web/updates/2017/02/navigation-preload
    if ('navigationPreload' in self.registration) {
      await self.registration.navigationPreload.enable();
    }
  })());

  // Tell the active service worker to take control of the page immediately.
  self.clients.claim();
});

self.addEventListener('fetch', (event) => {
  // We only want to call event.respondWith() if this is a navigation request
  // for an HTML page.
  if (event.request.mode === 'navigate') {
    event.respondWith((async () => {
      try {
        // First, try to use the navigation preload response if it's supported.
        const preloadResponse = await event.preloadResponse;
        if (preloadResponse) {
          return preloadResponse;
        }

        const networkResponse = await fetch(event.request);
        return networkResponse;
      } catch (error) {
        // catch is only triggered if an exception is thrown, which is likely
        // due to a network error.
        // If fetch() returns a valid HTTP response with a response code in
        // the 4xx or 5xx range, the catch() will NOT be called.
        console.log('Fetch failed; returning offline page instead.', error);

        const cache = await caches.open(CACHE_NAME);
        const cachedResponse = await cache.match(OFFLINE_URL);
        return cachedResponse;
      }
    })());
  }

  // If our if() condition is false, then this fetch handler won't intercept the
  // request. If there are any other fetch handlers registered, they will get a
  // chance to call event.respondWith(). If no fetch handlers call
  // event.respondWith(), the request will be handled by the browser as if there
  // were no service worker involvement.
});