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.
3.5 KiB
title, order, status
| title | order | status |
|---|---|---|
| E04. Receive SSE on the Client | 51 | draft |
cpp-httplib ships a dedicated sse::SSEClient class. It handles auto-reconnect, per-event-name dispatch, and Last-Event-ID tracking for you — so receiving SSE is painless.
Basic usage
#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(); // blocking
Build an SSEClient with a Client and a path, register a callback with on_message(), and call start(). The event loop kicks in and automatically reconnects if the connection drops.
Dispatch by event name
When the server sends events with an event: field, register a handler per name via on_event().
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() is the generic fallback: it receives every event that has no handler registered through on_event(). With on_event("message", ...) registered as above, message events go there instead.
Connection lifecycle and errors
sse.on_open([] {
std::cout << "connected" << std::endl;
});
sse.on_error([](httplib::Error err) {
std::cerr << "error: " << httplib::to_string(err) << std::endl;
});
Hook into connection open and error events. Even when the error handler fires, SSEClient keeps trying to reconnect in the background. It stops after a 204, 403, or 404 response, or once the attempts set with set_max_reconnect_attempts() run out.
It also stops when an event, or a line still waiting for its end, grows past CPPHTTPLIB_SSE_MAX_EVENT_LENGTH (16MB by default, 0 for no limit). The error handler then gets Error::ExceedMaxPayloadSize. The client's set_payload_max_length() doesn't apply to the stream as a whole, since an event stream has no end.
Run asynchronously
If you don't want to block the main thread, use start_async().
sse.start_async();
// main thread continues to do other things
do_other_work();
// when you're done, stop it
sse.stop();
start_async() spawns a background thread to run the event loop. Use stop() to shut it down cleanly.
Configure reconnection
You can tune the reconnect interval and maximum retries.
sse.set_reconnect_interval(5000); // 5 seconds
sse.set_max_reconnect_attempts(10); // up to 10 (0 = unlimited)
If the server sends a retry: field, that takes precedence.
Automatic Last-Event-ID
SSEClient tracks the id of each received event internally and sends it back as Last-Event-ID on reconnect. As long as the server sends events with id:, this all works automatically.
An empty id: clears the stored id. An id: that can't be sent as a header value (one with NUL or other control characters, or with leading or trailing whitespace) is ignored, and the previous id stays.
std::cout << "last id: " << sse.last_event_id() << std::endl;
Use last_event_id() to read the current value.
Note:
SSEClient::start()blocks, which is fine for a one-off command-line tool. For GUI apps or embedded in a server, thestart_async()+stop()pair is the usual pattern.
For the server side, see E01. Implement an SSE server.