Files
cpp-httplib/docs-src/pages/ja/cookbook/e04-sse-client.md
yhirose 9bfd2ddf1c Fix README and docs pages that no longer match the code
Bring the READMEs and the docs pages (en and ja) in line with the
current header:

- Fix the client sample that does not compile, the Transfer-Encoding
  statement for default headers, the verifier callback comment, the
  thread pool spawn rule, the sanitize_filename description, and the
  inverted Accept-Encoding sentence.
- Describe recent behaviour: TLS errors behind Read/Write failures,
  Host validation, Connection: close for a body without length,
  content_reader rules, refused CONNECT, WebSocketClient proxies,
  CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT, the SSE event size limit, and
  the payload limit of the Stream API.
- Complete the API references of WebSocket, WebSocketClient and the
  stream:: helpers, and the SSE reconnect rules.
- Fix cookbook pages: keychain loading on every backend, received Close
  status, a multipart sample that trusted the client's file name, an
  echo sample that sent binary as text, SNI, pre-request handler scope,
  stop() with WebSocket handlers, and the thread pool notes.
- Restore the mutex in the LLM app's Chapter 5 code.
2026-10-18 10:13:57 -04:00

104 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "E04. SSEをクライアントで受信する"
order: 51
status: "draft"
---
cpp-httplibには`sse::SSEClient`という専用のクラスが用意されています。自動再接続、イベント名別のハンドラ、`Last-Event-ID`の管理まで面倒を見てくれるので、SSEを受信するときはこれを使うのが一番ラクです。
## 基本の使い方
```cpp
#include <httplib.h>
httplib::Client cli("http://localhost:8080");
httplib::sse::SSEClient sse(cli, "/events");
sse.on_message([](const httplib::sse::SSEMessage &msg) {
std::cout << "data: " << msg.data << std::endl;
});
sse.start(); // ブロッキング
```
`Client`と接続先パスを渡して`SSEClient`を作り、`on_message()`でコールバックを登録します。`start()`を呼ぶとイベントループが走り、接続が切れると自動で再接続を試みます。
## イベント名で分岐する
サーバーが`event:`を付けてイベントを送ってくる場合は、`on_event()`で名前ごとにハンドラを登録できます。
```cpp
sse.on_event("message", [](const auto &msg) {
std::cout << "chat: " << msg.data << std::endl;
});
sse.on_event("join", [](const auto &msg) {
std::cout << msg.data << " joined" << std::endl;
});
sse.on_event("leave", [](const auto &msg) {
std::cout << msg.data << " left" << std::endl;
});
```
`on_message()`は、`on_event()`で登録していない名前のイベントをまとめて受け取る汎用ハンドラです。上の例のように`on_event("message", ...)`を登録した場合、`message`イベントは`on_message()`ではなくそちらに届きます。
## 接続イベントとエラーハンドリング
```cpp
sse.on_open([] {
std::cout << "connected" << std::endl;
});
sse.on_error([](httplib::Error err) {
std::cerr << "error: " << httplib::to_string(err) << std::endl;
});
```
接続確立時やエラー発生時にもフックを挟めます。エラーハンドラが呼ばれても、`SSEClient`は内部で再接続を試みます。ただし、サーバーが204、403、404のいずれかを返したときや、`set_max_reconnect_attempts()`で決めた回数を使い切ったときは再接続しません。
また、1つのイベントや、まだ改行が来ていない行が`CPPHTTPLIB_SSE_MAX_EVENT_LENGTH`(デフォルトは16MB、0なら無制限)を超えたときも止まります。このときエラーハンドラには`Error::ExceedMaxPayloadSize`が渡されます。イベントストリームには終わりがないので、クライアントの`set_payload_max_length()`はストリーム全体には適用されません。
## 非同期で動かす
メインスレッドを塞ぎたくない場合は`start_async()`を使います。
```cpp
sse.start_async();
// メインスレッドは別の仕事を続ける
do_other_work();
// 終わったら止める
sse.stop();
```
`start_async()`は裏でスレッドを立ち上げてイベントループを回します。`stop()`でクリーンに止められます。
## 再接続の設定
再接続間隔や最大試行回数を調整できます。
```cpp
sse.set_reconnect_interval(5000); // 5秒
sse.set_max_reconnect_attempts(10); // 10回まで(0=無制限)
```
サーバー側で`retry:`フィールドを送っていると、そちらが優先されます。
## Last-Event-IDの自動管理
`SSEClient`は受信したイベントの`id`を内部で保持していて、再接続時に`Last-Event-ID`ヘッダーとして送ってくれます。この挙動はサーバー側で`id:`付きイベントを送っていれば自動で有効になります。
空の`id:`を受け取ると、保持しているIDはクリアされます。ヘッダーの値として送れない`id:`(NULなどの制御文字を含むものや、前後に空白があるもの)は無視され、それまでのIDがそのまま残ります。
```cpp
std::cout << "last id: " << sse.last_event_id() << std::endl;
```
現在のIDは`last_event_id()`で参照できます。
> **Note:** SSEClientの`start()`はブロッキングなので、単発のツールならそのまま使えますが、GUIアプリやサーバーに組み込むときは`start_async()` + `stop()`の組み合わせが基本です。
> サーバー側の実装は[E01. SSEサーバーを実装する](../e01-sse-server)を参照してください。