Skip to content
github-actions[bot] edited this page Jul 16, 2026 · 1 revision

Server-Sent Events(SSE)

wknet::sse 提供 WHATWG text/event-stream 客户端。API 形态对齐 WebSocket:Connect / Receive / Close,依赖已有 http::Session

完整签名见 SSE API

结论

主题 行为
方法 GET
Content-Type 默认要求 text/event-stream(可 RequireEventStreamContentType=false
解析 半包、CRLF/\n、comment、id/event/data/retry、多 data 行
Last-Event-ID 解析器跟踪;重连时自动注入请求头
重连 默认开;指数退避 + 尊重 retry:4xx 不重连
超时 ConnectTimeoutMs / IdleTimeoutMs / ReceiveTimeoutMs 分字段
传输 复用 Session 的 H1/H2/H3 路径(受策略约束)
非目标 SSE 服务端、POST body 型 SSE、流式 gzip/br 响应体(首版)

最小示例

#include <wknet/Wknet.h>

wknet::http::Session* session = nullptr;
wknet::http::SessionCreate(nullptr, &session);

wknet::sse::ConnectConfig cfg = wknet::sse::DefaultConnectConfig();
cfg.Url = "https://example.com/events";
cfg.UrlLength = 28;
// cfg.IdleTimeoutMs = 0;           // 长空闲流
// cfg.AutoReconnect = true;
// cfg.LastEventId = "42"; cfg.LastEventIdLength = 2;

wknet::sse::SseClient* client = nullptr;
NTSTATUS st = wknet::sse::ConnectEx(session, &cfg, &client);
if (NT_SUCCESS(st)) {
    for (;;) {
        wknet::sse::Event event = {};
        st = wknet::sse::Receive(client, &event);
        if (!NT_SUCCESS(st)) {
            break; // 取消、最终失败或不再重连的断开
        }
        // event.Type / Data / Id 在下次 Receive 或 Close 前有效
    }
    wknet::sse::Close(client);
}
wknet::http::SessionClose(session);

与「整包 HTTP」的区别

普通 Get / Send SSE SseClient
完成条件 整响应结束 长期流;事件增量交付
body 聚合到 Response 不聚合为完整 Response body
超时 历史路径偏「整次」 open / idle / receive 分字段
重试 仅安全方法连接级一次 STATUS_RETRY 应用层重连 + Last-Event-ID

底层:若你用 SendOptions.OnBody 做通用流式下载,回调可能多次到达,finalChunk 仅在结束时为 true。见 同步 HTTP

重连语义

  1. 流正常结束或可恢复网络错误且 AutoReconnect → 调度 delay(retry: 或指数退避)。
  2. OnReconnect 可选通知 attempt / delay / lastError / lastEventId(含事件 data)。
  3. 新请求带 Last-Event-ID(若有);ForceNew 连接。
  4. open 得到 4xx → 失败,进入重连循环。
  5. Close 中止 sleep 与阻塞 Receive

边界

  • 库注入 Accept / Cache-Control /(有 id 时)Last-Event-ID;调用方不得覆盖这些受控头。
  • 不记录事件正文到 Trace(见 日志)。
  • 同一 client 单线程 Receive;多线程并行未定义。
  • 支持范围见 能力边界

English

Server-Sent Events (SSE)

wknet::sse is a WHATWG text/event-stream client. API shape matches WebSocket: Connect / Receive / Close on an existing http::Session.

Full signatures: SSE API.

Summary

Topic Behavior
Method GET only
Content-Type Default requires text/event-stream (RequireEventStreamContentType)
Parse Partial chunks, CRLF/\n, comments, id/event/data/retry, multi-line data
Last-Event-ID Tracked by parser; reinjected on reconnect
Reconnect On by default; exponential backoff + retry:; no reconnect on 4xx open
Timeouts Separate ConnectTimeoutMs / IdleTimeoutMs / ReceiveTimeoutMs
Transport Session H1/H2/H3 paths (policy-bound)
Non-goals SSE server, POST-body SSE, streaming gzip/br bodies (v1)

Minimal example

#include <wknet/Wknet.h>

wknet::http::Session* session = nullptr;
wknet::http::SessionCreate(nullptr, &session);

wknet::sse::ConnectConfig cfg = wknet::sse::DefaultConnectConfig();
cfg.Url = "https://example.com/events";
cfg.UrlLength = 28;

wknet::sse::SseClient* client = nullptr;
NTSTATUS st = wknet::sse::ConnectEx(session, &cfg, &client);
if (NT_SUCCESS(st)) {
    for (;;) {
        wknet::sse::Event event = {};
        st = wknet::sse::Receive(client, &event);
        if (!NT_SUCCESS(st)) {
            break;
        }
        // event fields valid until next Receive or Close
    }
    wknet::sse::Close(client);
}
wknet::http::SessionClose(session);

vs whole-message HTTP

Get / Send SSE SseClient
Completion Full response Long-lived stream; events incrementally
Body Aggregated Response Not aggregated as a full Response body
Timeouts Historically whole-op oriented Split open / idle / receive
Retry One connection-level STATUS_RETRY for safe methods App-level reconnect + Last-Event-ID

When using SendOptions.OnBody for generic streaming downloads, callbacks may fire multiple times; finalChunk is true only at the real end. See Sync HTTP.

Reconnect semantics

  1. Stream ends or recoverable network error and AutoReconnect → schedule delay (retry: or exponential backoff).
  2. Optional OnReconnect reports attempt / delay / lastError / lastEventId (not event data).
  3. New request carries Last-Event-ID when known; ForceNew connection.
  4. Open yields 4xx → fail, no reconnect loop.
  5. Close aborts sleep and blocked Receive.

Boundaries

  • Library injects Accept / Cache-Control / (when present) Last-Event-ID; callers must not override these controlled headers.
  • Trace never logs event bodies (see Logging).
  • Single-threaded Receive per client; concurrent Receive is undefined.
  • Scope: Capability matrix.

Clone this wiki locally