SSE(Server-Sent Events)は、サーバーが単方向モードで単一のHTTP接続を通じてクライアントにストリーミングデータを送信できるようにするW3C標準です。WebSocketと違い、SSEは通常のHTTP上で動作し、クライアント側に特別なプロトコルやライブラリを必要としません。W3C HTML Living Standard(2025)仕様によると、EventSource APIは、Chrome、Firefox、Safari、Edgeを含むすべての現代的なブラウザでサポートされています。
まとめ
SSE(Server-Sent Events)は、ウェブサーバーが接続確立後にいつでもクライアントにデータを送信できるテクノロジーです。これはWHATWGによってHTML Living Standardの一部として標準化され、MIMEタイプtext/event-streamを使用します。SSEは、メッセージ識別子、イベントタイプ、再接続延赤を指定できるテキストデータの送信をサポートします。
双方向プロトコルとアップグレードリクエストが必要なWebSocketと違い、SSEは通常のHTTP上で動作します。サーバーはContent-Type: text/event-streamヘッダーを設定し、データをチャンク単位で送信し、接続を開いたままにします。クライアントは、ブラウザのEventSource APIを通じてデータを受信します。これは自動的にストリームを解析し、イベントを生成します。
CanIUse(2025)によると、EventSource APIはグローバルで97.5%のブラウザでサポートされています。Internet Explorerやいくつかのモバイルブラウザ(バージョン7.0以前のSamsung Internet)ではサポートされていません。これらの場合、XHRストリーミングを通じてEventSourceをエミュレートするポリフィルがあります。SSEはHTTP/1.1パイプライニングでは動作しませんが、HTTP/2サーバープッシュとは完全互換性があります。
SSEは2009年にServer-Sent DOM EventsとしてHTML5仕様の一部として提案されました。最初の実装はOpera 9.0、その後Firefox 6.0(2011)、Chrome 9.0(2011)、Safari 5.0(2010)で現れました。2015年に仕様はHTML Living Standardの独立したセクションに移されました。10年以上の歴史にもかかわらず、SSEは単方向であることからWebSocketほど人気がありません。
SSEの仕組みは以下の通りです。クライアントがサーバーエンドポイントのURLを持つEventSourceインスタンスを作成します。ブラウザはAccept: text/event-streamヘッダーを付したGETリクエストを送信します。サーバーはステータス200 OKとContent-Type: text/event-streamヘッダーで答え、その後event-stream形式でデータを送信し始めます。接続は、サーバーが終了シグナルを送るか、クライアントがclose()を呼ぶまで開いたままです。
サーバー側では、データはチャンク単位(chunked transfer encoding)で送信されます。各データチャンクは、フィールド行(event, data, id, retry)からなるテキストメッセージです。サーバーはいつでもメッセージを送信できるため、SSEは通知やステータス更新に最適です。WebSocketのように定期的なハートビートパケットのやり取りは必要ありませんが、retryフィールドが再接続頻度を制御します。
パフォーマンステスト(2024)によると、SSEはメッセージサイズ256バイトで、接続ごとに秒間上 10,000メッセージのスループットを提供します。サーバー側では、各SSE接続は約5–10 KBのメモリを消費し、1 GBのRAMであれば、あるサーバーで50,000以上の同時接続をサポートできます。これは、バイナリプロトコルがないためにWebSocketよりも大幅に少なくなっています。
text/event-stream形式は、各メッセージが改行文字で区切られた名前付きフィールドからなる簡単なテキストプロトコルです。各フィールドは“フィールド名: 値”の形式です。メッセージは2つの改行文字(\n\n)で区切られます。
サポートされているフィールド:event(イベントタイプ、デフォルトはmessage)、data(データ文字列、複数行可能)、id(最終イベント識別子、Last-Event-IDに保存)、retry(再接続時間(ミリ秒))。コメントはコロン(:)で始まり、パーサーによって無視されますが、ハートビートに使用できます。
| フィールド | 必須 | 目的 |
|---|---|---|
| event | なし | イベントタイプ(デフォルトはmessage) |
| data | あり | メッセージデータ文字列 |
| id | なし | Last-Event-ID用のイベント識別子 |
| retry | なし | 再接続延赤(ms) |
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001
event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000
event: close
data: Session ended
EventSource APIは、SSEを受信するための組み込みブラウザインターフェースです。接続を作成するには、エンドポイントのURLを使ってコンストラクタを呼ぶだけです。EventSourceは自動的に接続を確立し、再接続を処理し、入力メッセージをJavaScriptイベントに解析します。
EventSourceのイベント:open(接続確立)、message(イベント指定なしでメッセージを受信)、error(接続エラー)。カスタムイベント(event: custom)の場合は、イベント名でaddEventListenerを使用できます。EventSourceは再接続時に自動的にLast-Event-IDヘッダーを送信し、サーバーが中断された場所からストリームを再開できるようにします。
MDNドキュメント(2025)によると、EventSourceはCORSとクレデンシャル伝送(withCredentials)をサポートしています。カスタムヘッダーやリクエストボディを送信するにはEventSourceは不適切です—fetch + ReadableStreamを使ったマニュアル実装が必要です。EventSourceはバイナリデータをサポートしていません—テキストとJSONのみです。
const eventSource = new EventSource('/api/events/stream');
eventSource.addEventListener('open', () => {
console.log('SSE接続が開きました');
});
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('受信しました:', data);
renderUpdate(data);
});
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
showNotification(notification.text);
});
eventSource.addEventListener('error', (error) => {
console.error('SSEエラー:', error);
// ブラウザが自動再接続
});
// 接続を閉じる
eventSource.close();
SSEとWebSocketは、リアルタイムコミュニケーションのための異なるテクノロジーで、それぞれに得意とする分野があります。WebSocketは双方向データ取り換え(チャット、ゲーム、協力エディティング)に適しており、SSEはサーバーからクライアントへの単方向ストリーム(通知、ニュースフィード、ティッカー)に適しています。
主な違いは、WebSocketがHTTP/1.1からWebSocketプロトコル(ws://)へのアップグレードリクエストを必要とすることで、これは企業用プロキシでブロックされる可能性があります。SSEは通常のHTTP上で動作し、どのプロキシでも通し、サーバーの特別な設定も必要ありません。SSEは実装も簡単です—サーバーに追加のライブラリは不要で、HTTPレスポンスを正しく構成すればよいだけです。
比較テスト(2024)によると、単一サーバープロセスで、SSEはより簡単なプロトコルのおかげでWebSocketより30–50%多い接続をサポートします。ただし、SSEはレイテンシが高く(50–200 ms対10–50 msのWebSocket)なのは、SSEが完全な双方向バイナリフレームではなく、チャンクHTTPを使用するからです。
| 特徴 | SSE | WebSocket |
|---|---|---|
| 方向 | サーバー → クライアント | 双方向 |
| プロトコル | HTTP (text/event-stream) | ws:// / wss:// (RFC 6455) |
| ブラウザ | 97.5% (組み込みEventSource) | 97% (組み込みWebSocket) |
| データ | テキスト / JSONのみ | テキスト + バイナリ (Blob, ArrayBuffer) |
| プロキシ処理 | どのプロキシでも通る | プロキシ設定が必要 |
| 再接続 | 自動 (ブラウザ) | マニュアル実装 |
| 履歴 | Last-Event-ID | 組み込みの履歴なし |
サーバーでのSSE実装にはライブラリが必要ありません—正しいHTTPヘッダーを設定し、text/event-stream形式でデータを送信するだけです。組み込みのhttpモジュールを使用したNode.jsの例を見てみましょう。サーバーはContent-TypeとCache-Controlヘッダーを設定し、N秒ごとにメッセージを送信します。
MDN Web Docs(2025)によると、SSEに必要なヘッダーは、Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-aliveです。Cache-Controlがないと、ブラウザがSSEストリームをキャッシュする可能性があり、配信が停止します。Connection: keep-aliveは、ブラウザに接続を開いたままにするよう明示的に指示します。
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let eventId = 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`event: update\n`);
res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
}).listen(3000);
from flask import Response, Flask
import time
import json
app = Flask(__name__)
@app.route('/stream')
def stream():
def generate():
event_id = 0
while True:
event_id += 1
data = json.dumps(
{'ticker': 'AAPL', 'price': 150.25})
yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
time.sleep(1)
return Response(generate(),
mimetype='text/event-stream')
モバイルアプリでのSSEの使用は、iOSやAndroidにネイティブなEventSource実装がないために制限されています。モバイルプラットフォームでは、SSEはサードパーティライブラリを通じて実装されます:iOSではURLSessionとNSURLProtocolを使用し、AndroidではOkHttpとSSEサポート(okhttp-sse)を使用します。React NativeやFlutterには、EventSourceをエミュレートするパッケージが用意されています。
iOSでは、SSEのネイティブ実装はURLSessionDataDelegateを通じて可能です。urlSession(_:dataTask:didReceive:)メソッドでデータを受信する際、アプリはバッファを簯積し、event-stream形式をマニュアルで解析します。iOS開発ブログ(2024)によると、ハートビートパケットがないため、iOSでのSSEの電池消費は一定的なWebSocket接続より40%低くなっています。
Androidでは、OkHttpがSSEストリームにサブスクライブするためのEventSource.Factoryクラスを提供しています。Androidアプリは、FCMが利用不可な場合の通知や、バックグラウンドのデータ同期にSSEを使用できます。AndroidでのSSEは、長期間のバックグラウンドタスクにWorkManagerと組み合わせて良く動作します。OkHttpドキュメント(2025)によると、okhttp-sseはカスタムリスナーで自動再接続をサポートしています。
よくある質問
SSEはHTTP上での単方向伝送(サーバー → クライアント)で、クライアント側にライブラリは不要です。WebSocketはバイナリプロトコルによる双方向伝送です。SSEは実装が簡単で、WebSocketはクライアントもデータを送信するタスクに適しています。
いいえ、SSEはテキストデータのみを伝送します。バイナリデータ(画像、音声)にはBase64エンコードが必要で、サイズが33%増加します。バイナリストリームにはWebSocketを使用するほうが良いです。
EventSourceは切断が発生したときに自動的に再接続します。延赤時間はストリームでretryフィールド(デフォルト1000 ms)で設定されます。再接続時にブラウザはLast-Event-IDヘッダーを送信し、サーバーが中断された場所からストリームを再開できるようにします。
各ブラウザには、同じドメインへの同時HTTP接続の制限があります。HTTP/1.1の場合はドメインごとに6–8接続、HTTP/2の場合は最大100接続です。SSEは1つの接続を使用するため、他のリクエストと競合することはありません。
SSEはメッセージの受信(入力)のみに適しています。メッセージの送信(出力)には、別途HTTPリクエスト(POST)が必要です。完全なチャットには、単一接続で双方向コミュニケーションを提供するWebSocketやSocket.IOを使用するのが便利です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。