5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめまして、花王株式会社の @TsuchiyaK です。

生成AIチャットアプリなどで「AIの回答をリアルタイムに順次表示したい」という要件はよくあるかと思います。
その際によく使われるのが Server-Sent Events (SSE) です。

本記事では、SSEの概要と、フロントエンドでの実装方法についてまとめます。

Server-Sent Events (SSE)とは?

SSEは、サーバーからクライアント(主にWebブラウザ)へ、一方向にリアルタイムでデータをプッシュするための仕組みです。
WebSocketと違い、クライアント→サーバーの通信はできませんが、HTTP/1.1ベースで実装がシンプル、サーバー側の負担も比較的軽いのが特徴です。

生成AIチャットアプリでは、AIの回答を「一文字ずつ」や「一文ずつ」ストリーミング表示する際によく使われます。


クライアント側のSSE実装方法

SSEを受け取る方法はいくつかあります。代表的なものを3つ紹介します。

1. EventSource

EventSourceオブジェクトを使い、サーバーとコネクションを張りっぱなしにしてtext/event-stream形式のデータを受信します。

const eventSource = new EventSource('/sse-endpoint');
eventSource.onmessage = (event) => {
  console.log(event.data); // サーバーからのデータ
};

メリット

  • 実装が簡単で、ブラウザ標準対応
  • 自動で再接続される

デメリット

  • HTTPメソッドはGETのみ(POST不可)
  • カスタムヘッダーが付けられないため、CORSや認証に工夫が必要な場合がある

2. fetch + ReadableStream

fetchでSSEエンドポイントにアクセスし、ReadableStreamでストリームを逐次処理します。
バイナリデータをテキストにデコードし、必要に応じてJSONにパースします。

const response = await fetch('/sse-endpoint');
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  // bufferを適宜パースして利用
}

メリット

  • POSTやカスタムヘッダーが利用可能
  • 細かい制御や独自プロトコルにも対応しやすい

デメリット

  • 自動再接続などの仕組みは自前で実装が必要
  • 実装がやや複雑

3. Axios

HTTPクライアントライブラリのAxiosを使用してresponseType: 'stream'を指定することでストリームレスポンスを受け取れますが、これはNode.js環境限定です。
ブラウザ環境のXMLHttpRequestのResponseTypeでは'stream'は使えません。

参考:Interface XMLHttpRequest

// Node.jsの場合
const axios = require('axios');
const response = await axios.get('/sse-endpoint', { responseType: 'stream' });
response.data.on('data', (chunk) => {
  console.log(chunk.toString());
});

メリット

  • Node.js環境でのストリーム処理が簡単

デメリット

  • ブラウザ環境ではresponseType: 'stream'が使えない

ブラウザでAxiosを使いたい場合

adapter: 'fetch'を指定することで、2.のfetchと同様の方法でストリームを受け取れます。

参考:Fetch adapter | axios | promise based HTTP client

import axios from 'axios';

const response = await axios.get('/sse-endpoint', {
  adapter: 'fetch'
  // 他のfetchオプションも指定可能
});
// response.bodyはReadableStream

まとめ

  • SSEは生成AIチャットアプリなどで「リアルタイムにサーバーからデータを受け取る」用途に便利
  • 実装方法は用途や環境に応じて選択(EventSource, fetch, Axios)
  • 認証やPOSTリクエストが必要な場合はfetchが柔軟

SSEを活用して、よりリッチなリアルタイムWeb体験を実現しましょう!


参考

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?