渐进式 Web 应用程序:连接再次启动时如何检测和处理

Progressive Web App: How to detect and handle when connection is up again

使用 PWA,我们可以在离线模式下处理设备连接断开的情况。但是我们如何检测固定网络连接并自动 reload/re-activate 应用程序?

我见过的大多数服务都使用以下做法:随着超时增加到某个值,尝试联系服务器。当达到最大超时值时,会出现一个带有手动重新连接按钮的指示器,指示下一次重新连接尝试发生的次数

您可以监视 offline and online events, which are widely supported。此外,您可以通过尝试从目标服务器 URL:

获取 HEAD 来测试连接性

// Test this by running the code snippet below and then
// use the "Offline" checkbox in DevTools Network panel

window.addEventListener('online', handleConnection);
window.addEventListener('offline', handleConnection);

function handleConnection() {
  if (navigator.onLine) {
    isReachable(getServerUrl()).then(function(online) {
      if (online) {
        // handle online status
        console.log('online');
      } else {
        console.log('no connectivity');
      }
    });
  } else {
    // handle offline status
    console.log('offline');
  }
}

function isReachable(url) {
  /**
   * Note: fetch() still "succeeds" for 404s on subdirectories,
   * which is ok when only testing for domain reachability.
   *
   * Example:
   *   https://google.com/noexist does not throw
   *   https://noexist.com/noexist does throw
   */
  return fetch(url, { method: 'HEAD', mode: 'no-cors' })
    .then(function(resp) {
      return resp && (resp.ok || resp.type === 'opaque');
    })
    .catch(function(err) {
      console.warn('[conn test failure]:', err);
    });
}

function getServerUrl() {
  return document.getElementById('serverUrl').value || window.location.origin;
}
<fieldset>
  <label>
    <span>Server URL for connectivity test:</span>
    <input id="serverUrl" style="width: 100%">
  </label>
</fieldset>
<script>document.getElementById('serverUrl').value = window.location.origin;</script>

<p>
  <i>Use Network Panel in DevTools to toggle Offline status</i>
</p>

一个 technique 处理这个:

  • 线下活动

    • 离线显示icon/status
    • 仅启用离线可用的功能(通过缓存数据)
  • 线上活动

    • 在线展示icon/status
    • 启用所有功能

注意 online 事件,它只在连接时通知设备。它可以连接到 WiFi 热点,而无需实际的互联网连接(例如,由于凭据)。

PWA 中的一个常见做法是对您的应用程序遵循 Application Shell 方法。这将允许您在进入时缓存应用程序 Shell,然后根据连接加载数据。

在这种方法中,最常用的缓存和服务方法是从缓存提供回退到网络,只要请求的资源在缓存中不可用,您就会通过网络发送请求并缓存响应。然后从缓存中提供服务。

这允许在连接不稳定时(例如在火车上)进行更优雅的降级。

一个实现的例子:

const cacheName = "my-cache-v1"

self.addEventListener('fetch', (event) => {
  if (event.request.method === 'GET') {
    event.respondWith(
      caches.match(event.request).then((response) => {
        if (response) {
          return response;
        }
        return fetch(event.request).then((response) => {
          return caches.open(cacheName).then((cache) => {
            cache.put(event.request.url, response.clone());
            return response;
          });
        });
      })
    );
  }
});

在上面的示例中(只是 Service Worker 生命周期中的必需步骤之一),您还需要删除过时的缓存条目。