SSE は『単方向ストリーミング』の HTTP 標準
Server-Sent Events (SSE) はサーバー→クライアントの単方向ストリーミングを HTTP 標準で実現します。本記事では編集部の視点で、SSE の実装と落とし穴を公開情報をもとに整理します。WebSocket 実践 もご参考に。
SSE と他技術の比較
(1) SSE:単方向(サーバー→クライアント)・HTTP/1.1 OK・自動再接続。(2) WebSocket:双方向・カスタムプロトコル・拡張容易。(3) Long Polling:旧来手法・実装簡単・効率悪。(4> HTTP/2 Push:規格はあるが採用低調。(5) 判断軸:単方向で十分なら SSE、双方向なら WebSocket。LLM のストリーミング応答で SSE が広く使われます。
SSE の基本仕様
(1) Content-Type:text/event-stream。(2) data: と event: と id:のフィールド。(3) retry:でリトライ間隔指定。(4) Last-Event-IDヘッダで再開。(5) ブラウザ標準 EventSource APIで受信。通信は通常の HTTP リクエストとして扱えます。
サーバ側実装
(1) レスポンスを開いたまま:close せず書き込み続ける。(2) flush 必須:バッファされると遅延。(3) Keep-Alive コメント:30秒ごと等で接続維持。(4) 同時接続数の制御:HTTP/1.1 はブラウザ単位6制限。(5) HTTP/2 推奨:多重化で接続数制限を回避。Next.js App Router の Route Handler は SSE 実装に向きます。
クライアント側実装
(1) EventSource を使う:標準ブラウザAPI。(2) onmessage / addEventListener("custom"):イベント受信。(3) onerror で再接続検知。(4) HTTP ヘッダ付与不可:標準APIの制限。(5) fetch + streams で代替:ヘッダ・認証カスタムが必要なら。
LLM ストリーミングでの使い方
(1) トークン生成ごとに data: event を送信。(2) JSON 行 (NDJSON) を使うパターンも。(3) OpenAI/Anthropic 互換:SSE が標準。(4) クライアントは progressive 表示。(5) キャンセル機能:AbortController で中断。AIコーディングエージェント比較 もご参考に。
本番運用の注意点
(1) プロキシ/ロードバランサ:バッファリング無効化必要(Nginx 等)。(2) タイムアウト設定:プロキシで切断されないように長め。(3) セルフホストvs CDN:CDN によっては SSE 非対応(Cloudflare 等は対応)。(4) サーバーレスの制約:長時間接続不可な環境あり。(5) 同時接続のスケール:1接続=1コネクション保持。CDN/Edge 実践 も合わせて。
失敗しがちなパターン
(1) Nginx バッファリングで遅延。(2) サーバーレス でタイムアウト:Lambda 15分上限。(3) 同時接続数で枯渇。(4) 再接続時の重複:Last-Event-ID 未対応。(5) HTTP/1.1 でブラウザ並列制限。対策は、(1)proxy_buffering off、(2)Cloud Run/EC2、(3)接続数監視、(4)id 採番+冪等、(5)HTTP/2 化、です。