Service Worker で WebSocket を使用する

このチュートリアルでは、Chrome 拡張機能のサービス ワーカーで WebSocket に接続する方法について説明します。GitHub で動作例をご覧いただけます。

背景

Chrome 116 以降、拡張機能 Service Worker での WebSockets のサポートが強化されます。以前は、30 秒間他の拡張機能イベントが発生しなかった場合、WebSocket 接続がアクティブであるにもかかわらず、サービス ワーカーが非アクティブになる可能性がありました。これにより、Service Worker が終了し、WebSocket 接続が終了します。拡張機能サービス ワーカーのライフサイクルの詳細については、拡張機能サービス ワーカー ガイドをご覧ください。

Chrome 116 以降では、30 秒の Service Worker アクティビティ ウィンドウ内でメッセージを交換することで、WebSocket 接続を有効にした Service Worker を維持できます。この処理は、サーバーまたは拡張機能から行うことができます。次の例では、Chrome 拡張機能からサーバーに通常のメッセージを送信して、サービス ワーカーが存続するようにします。

例: WebSocket キープアライブ

まず、マニフェストで Chrome の最小バージョンを 116 に設定して、拡張機能が Service Worker で WebSocket をサポートする Chrome バージョンでのみ実行されるようにする必要があります。

manifest.json:

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

20 秒ごとにキープアライブ メッセージを送信することで、Service Worker をアクティブに保つことができます。Service Worker が WebSocket に接続すると、キープアライブが開始されます。次の 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() 内では、アクティブな WebSocket 接続がある間に、setInterval(...) を使用してサーバーに 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 
  );
}