在 Service Worker 中使用 WebSocket

本教程演示了如何在 Chrome 扩展程序的 Service Worker 中连接到 WebSocket。您可以在 GitHub 上找到有效示例

背景

从 Chrome 116 开始,扩展程序服务工作线程对 WebSockets 的支持得到改进。之前,即使 WebSocket 连接处于活跃状态,如果 30 秒内没有发生其他扩展程序事件,Service Worker 也可能会变为非活跃状态。这会终止 Service Worker 并关闭 WebSocket 连接。如需详细了解扩展程序 Service Worker 生命周期,请参阅扩展程序 Service Worker 指南

从 Chrome 116 开始,您可以在 30 秒的 Service Worker 活动窗口内交换消息,从而保持具有 WebSocket 连接的 Service Worker 处于活动状态。这些请求可以从您的服务器或扩展程序发起。在以下示例中,我们将从 Chrome 扩展程序向服务器发送常规消息,以确保 Service Worker 保持活跃状态。

示例:WebSocket keepalive

首先,我们需要通过在清单中将最低 Chrome 版本设置为 116 来确保扩展程序仅在支持 Service Worker 中 WebSockets 的 Chrome 版本中运行:

manifest.json:

{
  ...
  "minimum_chrome_version": "116",
  ...
}

然后,我们可以每 20 秒发送一次 keepalive 消息,使 Service Worker 保持活跃状态。服务工作线程连接到 WebSocket 后,即会启动 keepalive。以下示例 WebSocket 客户端会在触发 onopen 事件时记录消息并调用 keepAlive()

service-worker.js

let webSocket = null;

function connect() {
  webSocket = new WebSocket('wss://example.com/ws');

  webSocket.onopen = (event) => {
    console.log('websocket open');
    keepAlive();
  };

  webSocket.onmessage = (event) => {
    console.log(`websocket received message: ${event.data}`);
  };

  webSocket.onclose = (event) => {
    console.log('websocket connection closed');
    webSocket = null;
  };
}

function disconnect() {
  if (webSocket == null) {
    return;
  }
  webSocket.close();
}

keepAlive() 中,我们使用 setInterval(...) 在 WebSocket 连接处于活跃状态时定期向服务器发送 ping:

function keepAlive() {
  const keepAliveIntervalId = setInterval(
    () => {
      if (webSocket) {
        webSocket.send('keepalive');
      } else {
        clearInterval(keepAliveIntervalId);
      }
    },
    // Set the interval to 20 seconds to prevent the service worker from becoming inactive.
    20 * 1000 
  );
}