要約
サーバーセンティッドイベント(SSE) は、平文HTTP上で構築されたサーバー→ブラウザの単向ストリーミングプロトコルです。ブラウザは new EventSource(url) と接続を開き、サーバーはその接続を維持し、必要に応じて data: の行をプッシュします。それだけです。WebSocketのハンドシェイクは不要で、ws://、アップグレードなし。自動的に再接続し、HTTPを話すすべてのプロキシを通じて動作し、2012年以来すべてのブラウザに搭載されています。
サーバー→クライアントのストリーミングが必要で、双方向メッセージングは必要ない場合、SSEは2026年に重要な点のほとんどにおいてWebSocketsを優勝しています。: より少ないコード、シンプルなインフラ、自動再接続、再開可能なための自動イベントID。WebSocketに手を伸ばす唯一の理由は双方向チャットスタイルのトラフィックやバイナリフレームです。
今すぐストリーミングを見たいですか?無料のSSEテスターを開きます、任意のSSEエンドポイントを貼り付け、イベントがライブで届くのを観察します。
30秒のマインドモデル
[ Browser ] ──── GET /events ───► [ Server ]
◄── HTTP 200, keep alive
◄── data: hello\n\n
◄── data: world\n\n
◄── data: ...
これは永続的なHTTP GETであり、決して閉じることがなく、レスポンスボディには特定のテキスト形式があります。MIMEタイプはtext/event-streamです。改行ごとにonmessageにイベントをフラッシュします。ブラウザがフレーミング、パース、再接続を処理します—あなたはeventSource.onmessage = ...を書けば終わりです.
最も小さな可能な例
サーバー(Node.js — ライブラリ不要):
import http from 'node:http';
http.createServer((req, res) => {
if (req.url !== '/events') {
res.writeHead(404).end();
return;
}
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
let n = 0;
const interval = setInterval(() => {
res.write(`data: tick ${++n}\n\n`);
}, 1000);
req.on('close', () => clearInterval(interval));
}).listen(3000);
クライアント(どこでも — <script> タグを含む):
const es = new EventSource('/events');
es.onmessage = (e) => console.log('got:', e.data);
es.onerror = () => console.warn('disconnected, browser will retry');
サーバーを実行し、クライアントをブラウザコンソールに貼り付けると、20行以下のコードでストリーミングが利用可能になります。ビルドステップなし。ライブラリなし。アップグレード交渉なし. それが全ての提案です.
2026年にSSEが低評価されている理由
「リアルタイム」と聞いただけでチームがWebSocketに無意識に手を伸ばし、その後1週間をプロキシのタイムアウト、スタickyセッション、ALBアップグレードヘッダーのデバッグに費やすことがあります。使用例の半分はサーバー→クライアントのみでした——フィード、通知ドロワー、ビルドログ、ライブカウンターです。これはSSEの領域です。
SSEで無料で得られるもの、WebSocketで自分で作る必要があるものは以下の通りです:
1. 自動再接続。 接続が切断されると、ブラウザは約3秒間待って再接続します。これにはコードを書く必要はありません。WebSocketsを使うと、キャリア全体でプロジェクトごとに同じバックオフループを書き続ける必要があります.
2. イベントIDと再開. サーバーがid: 42\nを送信すると、ブラウザは次回の再接続でヘッダーとしてLast-Event-ID: 42を送信します。サーバーはそこから再開できます。これはSSEがビルドログ、AIストリーミング、監査フィードに優れている機能です。WebSocketsを使えば、自分でカスタムプロトコルを設計できます.
3. 標準HTTPの使用です. SSEはGETでAccept: text/event-streamです。プロキシのすべて、CDNのすべて、WAFのすべて、リバースプロキシのすべてがそれを理解します(ただし、下記の注意点があります)。クッキー、AuthorizationCORS、圧縮 — すべて正常に動作しています。WebSocketsにはアップグレードのダンスが必要で、プロキシはしばしばそれを間違って扱います。
4. 言い訳はしない。テキストのみ、行区切りで。できますcurlSSEエンドポイントに接続して、ターミナルでストリームを読み取ってみてください。WebSocketでそれを試してみてください。
curl -N -H "Accept: text/event-stream" https://api.example.com/events
SSEフレームの構造
フォーマットは非常にシンプルだが、人々を混乱させることがある。各イベントは一つ以上の行で構成され、二つの改行で終了する(空行):
event: user-joined
id: 423
retry: 5000
data: {"userId":42,"name":"Ada"}
data: simple message
data: continuation of the same event
-
data:— これがペイロードである。同じイベント内の複数のdata:行は、\nで結合される. -
event:— イベントを設定名でes.addEventListener('user-joined', ...)を聞く。省略するとonmessageが発火します -
id:— 再接続時にブラウザがLast-Event-IDとして送り返すものです -
retry:— 再接続する前に待つミリ秒数です
。の空白行は必須です。二つ目を忘れる\nはSSEのバグ第1位です。プロキシ内のイベントバッファーとクライアントには何も見えません。
SSEとWebSocketsとロングポーリングの使用時期
これはあなたが必要とする唯一の決定木です:
SSEを使用するのは次のような場合:
- トラフィックがサーバー→クライアントのみ(通知、フィード、ダッシュボード、ログ、AIトークンストリーミング)
- 自動再接続を記述せずに実現したい
- テキストストリーミング(JSON、Markdownチャンク、ログ行)
- デバッグしたい場合
curl
WebSocketを使用するのは次の場合:
- 双方向で高頻度のトラフィックがある場合(チャット、協力編集、マルチプレイヤーゲーム)
- バイナリフレームが必要な場合(オーディオ/ビデオ、カスタムプロトコル)
- クライアント→サーバーメッセージの100ミリ秒未満のラウンドトリップが必要な場合
ロングポーリングを使用する場合:
- 上記の両方を壊すインフラに詰まっている場合(2026年では稀ですが、積極的な企業プロキシの背後で発生することがあります)
両側のコードでの完全なクラッシュは、SSE と WebSockets とロングポーリングの深掘りにあります。
三つの生産性の落とし穴
これらは、SSEを初めてリリースするたびに各チームに影響を与えるバグです.
1. プロキシバッファリングが致命的です
Nginxはデフォルトでレスポンスをバッファリングします。あなたのres.writeがバッファに入ります;クライアントは数分間何も見ません。2つの修正方法があります。両方を行ってください:
サーバーのレスポンスヘッダー:
X-Accel-Buffering: no
Nginxの設定:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 24h;
Cloudflareはバッファリングが多すぎる—SSEエンドポイントをキャッシュされないルートに置くか、Cloudflareに対応したストリーミング設定を使用する必要がある
2. ブラウザの1オリジンあたり6接続の制限
ブラウザは1オリジンあたり約6つのHTTP/1.1オープン接続に制限されています。あなたのアプリが接続を開く場合EventSource とユーザーがさらに5つのタブを開くと、7番目のタブが接続スロットがないためフリーズします。2つの解決策:
- HTTP/2 または HTTP/3 を使用 — 接続マルチプレクシングは、1つのTCP接続で数百のストリームを意味します。これは現代的な解決策です.
-
タブ間で
BroadcastChannelまたはSharedWorkerを通じて連携 — 一つのタブが EventSource を保持し、兄弟タブにイベントをブロードキャストします.
3. 心拍とアイドルタイムアウト
WebSocketと同じトラップ:ロードバランサーがアイドル接続を閉じます。AWS ALBのデフォルトは50秒です。15-30秒ごとにコメント行を送信します:
setInterval(() => res.write(':keepalive\n\n'), 15000);
:で始まる行は仕様に従ってコメントです — それらは接続を温めながら、トリガーを発火させませんonmessage はクライアント上で動作します。
認証とSSE
EventSource には一つ煩わしい制限があります:カスタムヘッダーを構築時に設定することができません。何もAuthorization: Bearer ...。あなたの選択肢は:
1. クッキー(ブラウザアプリケーションに推奨) — ブラウザが自動的に送信します。withCredentials: trueを使用し、CORSであなたのオリジンを許可してください。
const es = new EventSource('/events', { withCredentials: true });
2. クエリストリングトークン — 効作しますが、トークンはサーバーログに残ります
3. fetch + ReadableStream のパターン — EventSource を fetch で削除し、 は行動を起こしませんカスタムヘッダーを受け入れる。オートリコンネクトを失い、自分でフォーマットをパースしなければならないが、トークン認証を持つ現代のアプリにとって正しい選択だ。
const res = await fetch('/events', {
headers: { Authorization: `Bearer ${token}` },
});
const reader = res.body.getReader();
// ... parse text/event-stream chunks manually
図書館のような@microsoft/fetch-event-sourceこれをあなたのために行い、ほとんどの現代のAIストリーミングクライアントが内部で使用しています。
SSEはAIストリーミングを動力している
過去2年間、ChatGPTやClaude、あるいは他のAIチャットUIを使ったことがあるなら、SSEの動作を見てきました。サーバーはトークンが生成されるたびにストリーミングします:
data: {"choices":[{"delta":{"content":"Hello"}}]}
data: {"choices":[{"delta":{"content":" world"}}]}
data: [DONE]
Anthropic社、OpenAI社、Google社のストリーミングAPIはすべてSSE(または非常に似たカスタムイベントストリーム形式)を使用しています。SSEを知っていれば、他のウェブプロトコルと同じツールでAIストリーミングエンドポイントをデバッグできます。
SSEエンドポイントのテスト方法
使用する順序に従って三つの方法があります:
1. curl -N — バッファーフラグなし。最も速い健全性チェック。
curl -N -H "Accept: text/event-stream" https://api.example.com/events
2. ブラウザ内のSSEテスター — URLを貼り付け、イベントをリアルタイムで確認し、ヘッダーを確認し、再接続の挙動を確認します。こちらで無料で1つ入手、インストール不要です。
3. ブラウザデベロッパーツール → ネットワーク → イベントストリームタブ — アプリが開かれると、パースされたイベントストリームをリアルタイムで確認できます。Chromiumベースのブラウザにはそれ専用のタブがあります。
普通の誤解
- "SSEは死に、WebSocketsがそれを置き換えました。" WebSocketsは成長したが、SSEはどこにも行かなかった——AIストリーミング、GitHub Actionsログ、Vercelデプロイログ、Stripeウェブフック(まあ、技術的にはSSEではないが同じ考え方だ)、そして日々使用するほとんどの「通知」機能を動かしている
- 「SSEはHTTP/2と動作しない」 HTTP/2ではより良い動作する——6接続の制限がないし、すべてのストリームがマルチプル化される
- "SSEはテキストのみなのでバイナリを送信できません。" その通りですが、JSONフィールドで小さなバイナリペイロードをbase64でエンコードするのは問題ありません。実際のバイナリストリームの場合は、WebSocketを使用するか、単にHTTPダウンロードを使うべきです.
-
"SSEにはping/pongがありません。" 15秒ごとにコメント行(
:heartbeat\n\n)を送信します。完了です.
FAQ
SSEは長時間ポーリングと同じですか?
番号長ポーリングはクライアントがリクエストをし、サーバーがデータがあるまでそれを開いたままにし、サーバーが応答し、クライアントが別のリクエストを行います。SSEは一つのリクエストが永遠に開いたまま、サーバーがデータがあるときにプッシュします。長ポーリングは毎回接続を再開します。SSEはしません。
モバイルブラウザでSSEが動作しますか?
はい、iOSのSafari、Chrome Android、Firefox Mobileで完全にサポートしています。自動再接続はセルラーのハンドオフをうまく処理します。
React / Vue / Svelte / Solid で SSE を使えますか?
はい、どのようなサブスクリプションを使うかのように使えます。EventSource を useEffect(同等のもの)内でスピンアップし、クリーンアップ時に閉じ、各メッセージで状態を設定します。
サーバーが同時に処理できる SSE 接続の最大数はいくつですか?
Node.jsと賢明な設定で、各プロセスあたり数万もの接続が可能です—接続はほとんどアイドル状態で、それぞれ数KBのRAMを消費します。実際の上限として、各プロセスあたり約32k-65kのオープンファイル記述子と比較してください。
使うべきですかEventSourceまたはfetchプラスReadableStream?
使用EventSourceもしクッキー認証があなたにとってうまくいくなら(シンプルで無料の自動再接続)。使用fetch もし Authorization ヘッダーやカスタムリクエスト挙動が必要な場合、再接続を処理するライブラリを組み込んでください。
元々は AllDevToolsHub で公開されました。プライバシーを重視した無料のブラウザベースの開発ツール 250種類以上 — SSE テスター、WebSocket テスター、JWT デコーダーなど — については、alldevtoolshub.com をご覧ください。












