Service Worker で WebSocket を使用する

このチュートリアルでは、Chrome 拡張機能の Service Worker で WebSocket に接続する方法について説明します。動作するサンプルは GitHub で確認できます。

背景

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

Chrome 116 以降では、30 秒の Service Worker アクティビティ ウィンドウ内でメッセージを交換することで、WebSocket 接続を使用する Service Worker をアクティブに保つことができます。これは、サーバーまたは拡張機能から開始できます。次の例では、Chrome 拡張機能からサーバーに定期的にメッセージを送信して、Service Worker が動作し続けるようにします。

例: 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 
  );
}