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 をアクティブに保つことができます。これらは、サーバーまたは拡張機能から開始できます。次の例では、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() 内では、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 
  );
}