SJ blog
backend
S

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

WebSocketとServer-Sent Eventsの使い分け

リアルタイム通信の2大手法、WebSocketとSSE(Server-Sent Events)の違いを整理。チャット・通知・ライブデータなど用途別の選択基準と実装例を解説します。

一言結論

サーバーからの一方向通知(AI応答ストリーム・通知・ライブフィード)にはHTTP上で動き自動再接続するSSEで十分であり、双方向のリアルタイム通信(チャット・ゲーム)が必要な場合にのみWebSocketを選ぶのが正しい使い分けだ。

一言で違いを言うと

WebSocketSSE
通信方向双方向(サーバー ↔ クライアント)単方向(サーバー → クライアント)
プロトコルws:// / wss://HTTP(通常の https://)
再接続手動実装が必要自動(ブラウザが処理)
HTTPプロキシとの相性やや悪い良い
スケーリング難しい(接続を保持)HTTP と同等
ブラウザサポート全ブラウザ全ブラウザ(IE 除く)

SSE を選ぶべきケース

  • 通知・アラート: サーバーからの一方的な配信
  • ライブフィード: 株価・スポーツスコア・ニュース
  • AI ストリーミング: ChatGPT 風のトークン逐次配信
  • 進捗バー: ファイルアップロード・バッチ処理の進捗

SSE の実装(Node.js / Express)

// サーバー側
app.get("/events", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  // 接続ごとに ID を発行
  const clientId = Date.now();

  // 3秒ごとにデータを送信
  const timer = setInterval(() => {
    const data = { time: new Date().toISOString(), id: clientId };
    res.write(`data: ${JSON.stringify(data)}\n\n`);  // \n\n が重要
  }, 3000);

  req.on("close", () => {
    clearInterval(timer);
  });
});
// クライアント側(ブラウザ)
const eventSource = new EventSource("/events");

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("受信:", data);
};

// 名前付きイベント
eventSource.addEventListener("notification", (event) => {
  showNotification(JSON.parse(event.data));
});

eventSource.onerror = () => {
  console.log("接続エラー(自動再接続中)");
  // ブラウザが自動的に再接続する
};

WebSocket を選ぶべきケース

  • チャット: メッセージを双方向でリアルタイム送受信
  • ゲーム: クライアントの入力をサーバーに即時送信
  • コラボレーション: Google Docs 風の共同編集
  • トレーディング: 注文・キャンセルをリアルタイム送信

WebSocket の実装(Node.js / ws ライブラリ)

npm install ws
// サーバー側
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });
const clients = new Set<WebSocket>();

wss.on("connection", (ws) => {
  clients.add(ws);

  ws.on("message", (message) => {
    const data = JSON.parse(message.toString());

    // 全クライアントにブロードキャスト
    clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({ ...data, timestamp: Date.now() }));
      }
    });
  });

  ws.on("close", () => clients.delete(ws));
});
// クライアント側
const ws = new WebSocket("wss://example.com/chat");

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "join", room: "general" }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  appendMessage(data);
};

// 手動で再接続ロジックが必要
ws.onclose = () => {
  setTimeout(() => reconnect(), 3000);
};

AI ストリーミング(SSE の実用例)

// ChatGPT 風のトークンストリーミング
app.post("/chat", async (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");

  const stream = await openai.chat.completions.create({
    model: "gpt-5.4-mini",
    messages: req.body.messages,
    stream: true,
  });

  for await (const chunk of stream) {
    const token = chunk.choices[0]?.delta?.content ?? "";
    if (token) {
      res.write(`data: ${JSON.stringify({ token })}\n\n`);
    }
  }

  res.write("data: [DONE]\n\n");
  res.end();
});

まとめ

クライアント → サーバーの送信が必要?
  YES → WebSocket
  NO  → SSE(シンプルで自動再接続、プロキシとの相性も良い)

SSE は HTTP/2 で多重化できるため、スケールアウトが容易です。クライアントからの送信が不要なら、まず SSE を検討することを推奨します。


参考: MDN - Server-sent events / MDN - WebSocket