mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
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.
209 lines
5.1 KiB
Markdown
209 lines
5.1 KiB
Markdown
# SSEClient - Server-Sent Events Client
|
|
|
|
A simple, EventSource-like SSE client for C++11.
|
|
|
|
## Features
|
|
|
|
- **Auto-reconnect**: Automatically reconnects on connection loss or an error status (except 204, 403 and 404)
|
|
- **Last-Event-ID**: Sends last received ID on reconnect for resumption
|
|
- **retry field**: Respects server's reconnect interval
|
|
- **Event types**: Supports custom event types via `on_event()`
|
|
- **Async support**: Run in background thread with `start_async()`
|
|
- **C++11 compatible**: No C++14/17/20 features required
|
|
|
|
## Quick Start
|
|
|
|
```cpp
|
|
httplib::Client cli("http://localhost:8080");
|
|
httplib::sse::SSEClient sse(cli, "/events");
|
|
|
|
sse.on_message([](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << "Event: " << msg.event << std::endl;
|
|
std::cout << "Data: " << msg.data << std::endl;
|
|
});
|
|
|
|
sse.start(); // Blocking, with auto-reconnect
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### SSEMessage
|
|
|
|
```cpp
|
|
struct SSEMessage {
|
|
std::string event; // Event type (default: "message")
|
|
std::string data; // Event payload
|
|
std::string id; // Event ID
|
|
};
|
|
```
|
|
|
|
### SSEClient
|
|
|
|
#### Constructor
|
|
|
|
```cpp
|
|
// Basic
|
|
SSEClient(Client &client, const std::string &path);
|
|
|
|
// With custom headers
|
|
SSEClient(Client &client, const std::string &path, const Headers &headers);
|
|
```
|
|
|
|
#### Event Handlers
|
|
|
|
```cpp
|
|
// Called for events whose type has no on_event() handler
|
|
sse.on_message([](const SSEMessage &msg) { });
|
|
|
|
// Called for specific event types
|
|
sse.on_event("update", [](const SSEMessage &msg) { });
|
|
sse.on_event("delete", [](const SSEMessage &msg) { });
|
|
|
|
// Called when connection is established
|
|
sse.on_open([]() { });
|
|
|
|
// Called on connection errors
|
|
sse.on_error([](httplib::Error err) { });
|
|
```
|
|
|
|
#### Configuration
|
|
|
|
```cpp
|
|
// Set reconnect interval (default: 3000ms, minimum: 100ms)
|
|
sse.set_reconnect_interval(5000);
|
|
|
|
// Set max reconnect attempts (default: 0 = unlimited)
|
|
sse.set_max_reconnect_attempts(10);
|
|
|
|
// Update headers at any time (thread-safe)
|
|
sse.set_headers({{"Authorization", "Bearer new_token"}});
|
|
```
|
|
|
|
The client reconnects when it cannot connect or the stream ends. A status other than `200` calls `on_error(Error::Connection)`; a `204`, `403` or `404` then stops the client, and any other status, `401` included, reconnects, so an `on_error` handler can refresh credentials with `set_headers()`. `set_max_reconnect_attempts()` counts reconnect attempts in a row: the count starts over after each successful connection.
|
|
|
|
An event, or a line still waiting for its end, longer than `CPPHTTPLIB_SSE_MAX_EVENT_LENGTH` (16MB by default, `0` for no limit) ends the connection with `Error::ExceedMaxPayloadSize`, and the client stops rather than reconnect to the same event. The client's `set_payload_max_length()` does not apply to the stream as a whole, which has no end.
|
|
|
|
#### Control
|
|
|
|
```cpp
|
|
// Blocking start with auto-reconnect
|
|
sse.start();
|
|
|
|
// Non-blocking start (runs in background thread)
|
|
sse.start_async();
|
|
|
|
// Stop the client (thread-safe)
|
|
sse.stop();
|
|
```
|
|
|
|
#### State
|
|
|
|
```cpp
|
|
bool connected = sse.is_connected();
|
|
const std::string &id = sse.last_event_id();
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Basic Usage
|
|
|
|
```cpp
|
|
httplib::Client cli("http://localhost:8080");
|
|
httplib::sse::SSEClient sse(cli, "/events");
|
|
|
|
sse.on_message([](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << msg.data << std::endl;
|
|
});
|
|
|
|
sse.start();
|
|
```
|
|
|
|
### With Custom Event Types
|
|
|
|
```cpp
|
|
httplib::sse::SSEClient sse(cli, "/events");
|
|
|
|
sse.on_event("notification", [](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << "Notification: " << msg.data << std::endl;
|
|
});
|
|
|
|
sse.on_event("update", [](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << "Update: " << msg.data << std::endl;
|
|
});
|
|
|
|
sse.start();
|
|
```
|
|
|
|
### Async with Stop
|
|
|
|
```cpp
|
|
httplib::sse::SSEClient sse(cli, "/events");
|
|
|
|
sse.on_message([](const httplib::sse::SSEMessage &msg) {
|
|
std::cout << msg.data << std::endl;
|
|
});
|
|
|
|
sse.start_async(); // Returns immediately
|
|
|
|
// ... do other work ...
|
|
|
|
sse.stop(); // Stop when done
|
|
```
|
|
|
|
### With Custom Headers (e.g., Authentication)
|
|
|
|
```cpp
|
|
httplib::Headers headers = {
|
|
{"Authorization", "Bearer token123"}
|
|
};
|
|
|
|
httplib::sse::SSEClient sse(cli, "/events", headers);
|
|
sse.start();
|
|
```
|
|
|
|
### Refreshing Auth Token on Reconnect
|
|
|
|
```cpp
|
|
httplib::sse::SSEClient sse(cli, "/events",
|
|
{{"Authorization", "Bearer " + get_token()}});
|
|
|
|
// Preemptively refresh token on each successful connection
|
|
sse.on_open([&sse]() {
|
|
sse.set_headers({{"Authorization", "Bearer " + get_token()}});
|
|
});
|
|
|
|
// Or reactively refresh on auth failure (401 triggers reconnect)
|
|
sse.on_error([&sse](httplib::Error) {
|
|
sse.set_headers({{"Authorization", "Bearer " + refresh_token()}});
|
|
});
|
|
|
|
sse.start();
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```cpp
|
|
sse.on_error([](httplib::Error err) {
|
|
std::cerr << "Error: " << httplib::to_string(err) << std::endl;
|
|
});
|
|
|
|
sse.set_reconnect_interval(1000);
|
|
sse.set_max_reconnect_attempts(5);
|
|
|
|
sse.start();
|
|
```
|
|
|
|
## SSE Protocol
|
|
|
|
The client parses SSE format according to the [WHATWG HTML Living Standard](https://html.spec.whatwg.org/multipage/server-sent-events.html):
|
|
|
|
```
|
|
event: custom-type
|
|
id: 123
|
|
data: {"message": "hello"}
|
|
|
|
data: simple message
|
|
|
|
: this is a comment (ignored)
|
|
```
|