Setting up service workers on Vultr title. A gradient background with a shield icon in the top right and a JavaScript logo in the bottom right corner.
赞助

在 Vultr 上设置 Service Worker

阅读时间 6 分钟

Service workers 允许在 Web 浏览器中运行可脚本化的网络代理,使开发者能够控制网页如何响应网络请求、管理资源并构建健壮且高性能的 Web 应用。 在您的 Web 应用中学习使用 service workers 将帮助您构建诸如后台数据同步、预取用户接下来需要的资源、在一个地方而不是多个页面处理数据以及其他激动人心的功能。

在本文中,我们将了解 service worker 的生命周期以及理解它们的工作原理的重要性。我们还将创建一个托管在 Vultr 上的示例 Web 应用,包括通过 Nginx 和 Let's Encrypt 实现的 HTTPS,这是让 service worker 在用户浏览器上运行所必需的。

Service worker 生命周期

Service workers 是事件驱动的 JavaScript 后台任务,它们独立于 Web 页面的主线程运行。它们充当 Web 页面和网络之间的中介,提供离线支持、推送通知和后台同步等功能。

理解 service worker 的生命周期对于在 Web 项目中有效实现和管理它们至关重要。此生命周期包含三个主要阶段:

  • 注册:初始步骤是 注册阶段,在此阶段我们检查浏览器是否支持 service workers。
  • 安装:注册后,当用户访问网站时,service worker 会立即下载 用于 service worker 控制的 URL,并为指定的 URL 创建缓存。每当网站有新版本时,就会触发安装,并在后台安装新版本。
  • 激活:在激活阶段,service worker 会接管其作用域内的 Web 页面,并开始拦截网络请求。此阶段通常是清理旧缓存并执行任何必要的初始化任务的合适阶段。

在 Vultr 上设置项目目录

首先,请遵循我们上一篇文章中“在 Vultr 上部署服务器”部分中的步骤来部署服务器。此项目不需要特定的 Marketplace 应用。接下来,让我们通过 SSH 访问服务器终端,并为我们的 Web 应用设置一个项目。我们将创建一个带有 CSS 样式的着陆页,并在我们的主 JavaScript 文件中添加一个脚本,用于检查浏览器是否支持 service workers 并注册 service worker。

我们将使用 Nano 文本编辑器在服务器上创建和编辑项目文件。您可以在 快捷键备忘单 中查找使用 Nano 的帮助。

  1. 创建一个项目目录,并进入该目录。

    bash
    mkdir sample
    cd sample
    
  2. 创建一个 HTML 文件。

    bash
    nano index.html
    
  3. 将以下代码复制并粘贴到 index.html 文件中。

    html
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>My Service Worker App</title>
        <link rel="stylesheet" href="/main.css" />
      </head>
    
      <body>
        <h1>Welcome to My Service Worker App</h1>
    
        <p>This is a sample paragraph with <a href="#">a link</a>.</p>
    
        <script src="/app.js"></script>
      </body>
    </html>
    
  4. 保存并退出文件。

  5. 创建一个 CSS 文件。

    bash
    nano main.css
    
  6. 将以下代码复制并粘贴到 main.css 文件中。

    css
    body,
    h1 {
      margin: 0;
      padding: 0;
    }
    
    h1 {
      text-align: center;
      margin-top: 50px;
    }
    
    p {
      text-align: center;
    }
    
    body {
      background-color: #add8e6;
      font-family: Arial, sans-serif;
    }
    
    a {
      color: #00ff7b;
    }
    
    a:hover {
      text-decoration: underline;
    }
    
  7. 保存并关闭文件。

创建 Service Worker

现在您已经设置了项目目录,在本节中,您将探索 service worker 如何被注册、安装和激活。

安装和激活 Service Worker

让我们向项目中添加一个基本的 service worker,我们的主 JavaScript 应用可以与之交互。

  1. sample 目录中,创建一个 JavaScript 文件。

    bash
    nano sw.js
    
  2. 将以下代码复制并粘贴到 sw.js 文件中。

    js
    const CACHE_NAME = "my-cache-v1";
    const urlsToCache = ["/", "/index.html", "/main.css"];
    
    self.addEventListener("install", (event) => {
      event.waitUntil(
        caches.open(CACHE_NAME).then((cache) => {
          console.log("Opened cache");
          return cache.addAll(urlsToCache);
        }),
      );
    });
    
    self.addEventListener("activate", (event) => {
      event.waitUntil(
        caches.keys().then((cacheNames) => {
          return Promise.all(
            cacheNames
              .filter((cacheName) => {
                return cacheName !== CACHE_NAME;
              })
              .map((cacheName) => {
                return caches.delete(cacheName);
              }),
          );
        }),
      );
    });
    
    self.addEventListener("fetch", (event) => {
      event.respondWith(
        caches.match(event.request).then((response) => {
          if (response) {
            return response;
          }
          return fetch(event.request);
        }),
      );
    });
    
  3. 保存并退出文件。

在上面的代码中,我们挂钩了前面描述的三个事件。当触发安装事件时,我们打开一个缓存,用于我们希望控制的 URL。我们使用激活事件来清除可能拥有的任何旧缓存。最后,我们有一个 fetch 事件,它检查用户请求的资源是否已缓存;否则,它会从网络获取资源并返回。

注册 Service Worker

在本节中,您将学习如何检查浏览器是否支持 service workers,添加一个事件监听器来注册 service worker,并在 service worker 注册后显示一个警告。

  1. 创建一个 JavaScript 文件。

    bash
    nano app.js
    
  2. 将以下代码复制并粘贴到 app.js 文件中。

    js
    if ("serviceWorker" in navigator) {
      window.addEventListener("load", function () {
        navigator.serviceWorker
          .register("/sw.js")
          .then(function (registration) {
            alert(
              "Service Worker registration successful with scope: " +
                registration.scope,
            );
            if (registration.installing) {
              console.log("Service worker installing");
            } else if (registration.waiting) {
              console.log("Service worker installed");
            } else if (registration.active) {
              console.log("Service worker active");
            }
          })
          .catch(function (err) {
            alert("Service Worker registration failed: " + err);
          });
      });
    }
    
  3. 保存并关闭文件。

在上面的代码中,if ('serviceWorker' in navigator) 条件语句检查浏览器是否支持 service workers。如果我们支持 service workers,我们可以使用 navigator.serviceWorker.register() 方法进行注册,该方法提供位于 /sw.js 的脚本。我们正在显示一个打印作用域 URL 的警告,并将生命周期状态记录到控制台。

在 Vultr 服务器上提供 Web 应用

在本节中,您将学习如何创建一个 systemd 服务,该服务在系统启动时自动启动,并运行一个 Python HTTP 服务器来提供 Web 应用。

  1. 退出 sample 目录。

    bash
    cd ..
    
  2. 创建一个 Python 文件。

    bash
    nano http_server.py
    
  3. 将以下代码复制并粘贴到 http_server.py 文件中。

    python
    import http.server
    import socketserver
    import os
    
    PORT = 8000
    DIRECTORY = "sample"
    
    sample_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sample")
    
    mime_types = {
       ".html": "text/html",
       ".css": "text/css",
       ".js": "application/javascript",
    }
    class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
       def guess_type(self, path):
          _, ext = os.path.splitext(path)
          return mime_types.get(ext.lower(), "application/octet-stream")
    Handler = MyHTTPRequestHandler
    
    os.chdir(sample_dir)
    
    with socketserver.TCPServer(("", PORT), Handler) as httpd:
       print("Serving at port", PORT)
       httpd.serve_forever()
    
  4. 上面的代码在我们的 sample 目录中启动一个端口为 8000 的 Python HTTP 服务器。

  5. 保存并退出文件。

  6. 允许执行 http_server.py 作为脚本的权限。

    bash
    chmod +x http_server.py
    
  7. 创建一个 service worker 服务文件。

    bash
    sudo nano /etc/systemd/system/pythonserver.service
    
  8. 将以下内容粘贴到服务文件中。请务必将 UserGroup 值替换为您实际的值。另外,将 WorkingDirectory 替换为实际的 sample 目录路径,并将 ExecStart 替换为实际的 http_server.py 路径。

    [Unit]
    Description= Daemon for Sample Demo Application
    After=network.target
    
    [Service]
    User=example_user
    Group=example_user
    WorkingDirectory= /example_user/sample
    ExecStart= /usr/bin/python3 /example_user/http_server.py
    
    [Install]
    WantedBy=multi-user.target
    
  9. 启动服务。

    bash
    sudo systemctl start pythonserver
    
  10. 验证服务状态。

    bash
    sudo systemctl status pythonserver
    
  11. 输出将如下所示。

    ● pythonserver.service - Daemon for Sample Demo Application
       Loaded: loaded (/etc/systemd/system/pythonserver.service; disabled; preset: enabled)
       Active: active (running) since Fri 2024-04-05 10:29:31 UTC; 3s ago
    Main PID: 10181 (python3)
       Tasks: 1 (limit: 1011)
       Memory: 8.6M
          CPU: 43ms
       CGroup: /system.slice/pythonserver.service
                └─10181 /usr/bin/python3 /example_user/http_server.py
    
  12. 启用该服务,以便在系统每次启动时自动启动。

    bash
    sudo systemctl enable pythonserver
    

使用 HTTPS 保护 Vultr 上的 Web 应用

出于安全原因,Service workers 仅在 HTTPS 上下文中运行。这可以防止中间人攻击,并降低通过网络拦截和篡改数据的风险。

第一步是为您的 Web 应用配置反向代理。我们可以使用 Nginx 来高效地处理请求和负载均衡。接下来,您需要从 Let's Encrypt 请求一个免费的 SSL 证书来添加 HTTPS。执行此操作的步骤在我们之前的文章“将 Nginx 配置为反向代理服务器并使用 Certbot 安装 SSL 证书”中有描述。

应用 HTTPS 后,请访问您的应用程序 URL,如果一切正常,您将看到一个带有 service worker 作用域的警告。您还可以检查浏览器的开发者控制台来查看生命周期事件。第一次访问页面时,将打开缓存,并且 service worker 将被安装。您可以刷新页面以查看 service worker 已激活,并且用户可以在离线状态下访问网页。要进行测试,您可以关闭互联网连接并再次刷新页面。

A web page with an alert box saying "Service Worker registration successful with scope:" followed by a redacted server URL.

总结

在本文中,我们了解了 service workers 是什么以及它们的生命周期的不同阶段。我们还学习了如何创建一个具有 service worker 的 Web 应用,该应用为特定页面和资源添加离线功能。使用 service workers 可以显著改善用户体验,因为它允许用户即使在离线状态下也能访问内容。

这是一篇 Vultr 的赞助文章。Vultr 是全球最大的私营云计算平台。Vultr 深受开发者喜爱,已为 185 个国家的 150 万多客户提供服务,提供灵活、可伸缩的全球云计算、云 GPU、裸金属和云存储解决方案。了解更多关于 Vultr 的信息。