😼

初学者向け: Server-Sent Events(SSE)の徹底解説と実装方法

2024/11/11に公開

サーバー送信イベント(Server-Sent Events、SSE)とは、Webブラウザーとサーバー間の一方向の非同期通信方法のことです。最近、サーバー送信イベントは、リアルタイム通信の実現によく利用されています。本文では、サーバー送信イベントを詳しく解説した上、それを実現する方法を皆さんに紹介します。

サーバー送信イベント(Server-Sent Events)とは

サーバー送信イベント(Server-Sent Events、SSE)とは、Webブラウザーとサーバー間の一方向の非同期通信方法のことです。この通信方法では、サーバーがブラウザーに対してイベントをプッシュ送信でき、ブラウザーはサーバーから送信されたイベントを受信して処理できます。

SSEはHTTPプロトコルに基づいているため、サーバーとブラウザー間は長時間接続を維持でき、テキスト形式でデータ送受信を行います。長時間接続でもリソース消費が少ないため、リアルタイムな通信に向いているのが特徴です。

Server-Sent Eventsの利用シーン

最近、リアルタイムの通信を実現するために、サーバー送信イベントがよく利用されるので、比較的に人気な通信技術になっています。実際には、サーバー送信イベントは、リアルタイムの通信の実現だけに機能しているわけではなく、他にも様々な役割を果たすこともできます。一般的には、サーバー送信イベント(SSE)の利用シーンは次のようになります。

  • リアルタイム通信の実現: 従来のHTTP通信ではクライアントからのリクエストに対してのみサーバーがレスポンスを返すことで、ステートレスになりますが、SSEを使うことでサーバーからクライアントへリアルタイムにデータをプッシュできます。これによりチャットやライブ更新などが実装できます

  • サーバー負荷の軽減: 従来クライアントが周期的にポーリングしていた場合、頻繁なリクエスト送信でサーバー負荷が高くなります。SSEなら長時間接続を使い負荷を抑えられます

  • データ通信の効率化: ポーリングではサーバー側に更新がない場合でも頻繁にリクエストを送信します。SSEなら更新時のみデータを送信するので通信効率が良いです

  • ストリーミング通信: SSEではHTTPを利用してストリーミングでデータを送受信できます。ビデオや音声などのストリーミングにも利用できます

  • ブラウザーの対応: 主要ブラウザーがSSEに対応しているため、特別なライブラリなしに利用できるのが強みです

このような理由から、リアルタイムWebアプリケーションを開発する際だけではなく、他の場面でもSSEが有用な通信手段になる可能性もあると言えます。

JavaScriptでServer-Sent Events(サーバー送信イベント)の実装

ブラウザー側ではJavaScriptのEventSourceオブジェクトを使ってSSEを受信し、サーバー側はHTTPのレスポンスヘッダーを操作してストリーム形式でデータを送信します。

Server-Sent Events (SSE) のContent-Type

Server-Sent Events (SSE) は、サーバーからクライアントへの一方向の通信を実現するストリーミングデータの伝送方式です。SSEのレスポンスヘッダのContent-Typeには以下のように指定します。

Content-Type: text/event-stream

この値はSSEの仕様で定められており、クライアントがSSEのストリームデータであることを認識するために必要となります。

サーバー側の実装

  • HTTPレスポンスヘッダーに以下を設定
  • Content-Type: text/event-stream
  • Cache-Control: no-cache
  • Connection: keep-alive
  • データはイベントストリーム形式で送信
  • id: イベントの固有ID
  • event: イベント名
  • data: 送信データ
  • flushメソッドでデータをフラッシュ

【サーバー側のサンプルコード】

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); 

while(true){

  // データをJSON形式で作成
  $data = json_encode(['message' => 'Hello!', 'time' => date('r')]);
  
  // データを書き出し   
  echo "event: message\n";
  echo "data: {$data}\n\n";
  
  ob_flush();
  flush();
  
  // 一定間隔でデータを送信
  sleep(1);
}

クライアント側の実装

  • EventSourceオブジェクトを生成
  • new EventSource(URL)
  • addEventListenerでイベントを listens
  • イベントハンドラで受信データを処理
  • SSE接続が切れた時の処理

サーバー送信イベント(SSE)の簡単な実装例は以下のようになります。

【クライアント側のサンプルコード】

// EventSourceオブジェクトを生成
const eventSource = new EventSource('/sse-endpoint');

// メッセージイベントのリスナーを設定
eventSource.addEventListener('message', (e) => {
  const data = JSON.parse(e.data);
  console.log(data); 
});

// SSEが切断された時の処理  
eventSource.onerror = () => {
  console.log('SSE disconnected!');
  eventSource.close();
};

このようにサーバー側でHTTPレスポンスをストリーミング形式にし、クライアント側でEventSourceを使ってイベントリスナーを登録するのが基本的な実装パターンです。

Apidogで簡単にサーバー送信イベントを実装

Apidogは、サーバー送信イベントに対応できるAPIクライアントです。Apidogを使うことで、非常に直感的な操作で、サーバー送信イベントを実装する事ができます。コードを書かずにサーバー送信イベントを実装したい場合は、Apidogは一番適切なソリューションになると思います。

Server-Sent Events接続の開始

SSE 接続を開始するには、HTTP プロジェクトで新しい API を作成します。リクエストの送信後、レスポンスの Content-Typetext/event-stream が含まれている場合、Apidog は自動的に返されたデータを SSE イベントとして解析し、新しいタイムラインビューでレスポンスの内容をリアルタイムに更新します。

sse-chatgpt-1.png

後処理でメッセージ内容の抽出

現在のAPIの後処理でカスタムスクリプトを追加して、各 SSE イベントから特定のフィールド値を抽出し、完全な文字列に連結します。

上記の図に示した APIを例に取ると、この APIで返されるメッセージには JSONデータが含まれています。 answer フィールドからパラメーターの内容を抽出して、完全なテキストに連結します。

sse-chatgpt-2.png

カスタム スクリプトに以下の例のコードを記述します。

// レスポンス テキストを取得
const text = pm.response.text() 
// テキストを行に分割
var lines = text.split('\n');   
// "content"パラメータを格納する空の配列を作成  
var contents = [];
// 各行を反復処理
for (var i = 0; i < lines.length; i++) {
    const line = lines[i];
    // "data:"で始まらない行はスキップ 
    if (!line.startsWith('data:')) {
        continue;
    }
    // JSON データを解析
    try {
        var data = JSON.parse(line.substring(5).trim()); // 先頭の "data: " を削除
        // "choices" 配列から "content" パラメーターを取得し、配列に追加
        contents.push(data.choices[0].delta.content); 
    } catch (e) {
        // 有効なJSONデータでない場合は現在の行を無視
    }
}
// "content" パラメーターを join() メソッドを使用して連結
var result = contents.join('');
// 結果を本文の "Visualize" タブに表示
pm.visualizer.set(result);
// 結果をコンソールに出力  
console.log(result);

リクエストの送信後、連結されたテキストは「コンソール」で確認できます。

sse-chatgpt-3.png

まとめ

本記事では、Server-Sent Events(SSE)について詳しく解説しました。

  • SSEはHTTPプロトコルに基づく一方向の非同期通信方式
  • サーバーからクライアントへのプッシュ通信が可能
  • リアルタイム通信の実現やサーバー負荷軽減などに活用できる
  • 主要ブラウザーに標準対応しており、JavaScriptのEventSourceで実装可能
  • サーバー側ではレスポンスヘッダを設定し、イベントストリーム形式でデータを送信
  • クライアント側ではEventSourceでストリームを受信し、イベントリスナーを登録

SSEはシンプルさと高パフォーマンスが特徴的な通信方式です。リアルタイムWebアプリケーションはもちろん、様々な用途に活用できるでしょう。一方で双方向通信が必要な場合はWebSocketsを利用する必要があります。

今後ますますリアルタイム性が求められるWebアプリケーション開発において、Server-Sent Eventsの理解と実装スキルは重要になってくると考えられます。

最後まで読んでくださり、ありがとうございました!
この記事を読んで少しでも理解を深めていただければ幸いです!

Discussion