- 后端
- 网络
【免费下载链接】cpp-httplib
A C++ header-only HTTP/HTTPS server and client library
恭喜你完成了 cpp-httplib Tour 全部章节的学习!你已经掌握了httplib::Client与httplib::Server的基本用法、路由、静态文件与 TLS/HTTPS 配置。本篇将系统性地介绍 Tour 中未覆盖的进阶特性:流式 API、Server-Sent Events、认证、压缩、代理、超时、Keep-Alive、中间件、日志与 Unix Domain Socket,帮助你把这些能力直接运用到 LLM 流式响应、大文件上传下载、实时推送和同机进程通信等实战场景中。读完本篇,你将能够在 cpp-httplib 项目中独立实现分块处理、自动重连的 SSE 客户端、带认证与压缩的 HTTPS 服务等完整方案。
流式 API:分块处理响应与请求
无论是处理 LLM 流式生成响应,还是下载大文件,把整个响应一次性加载进内存都是不可接受的。cpp-httplib 提供独立的stream命名空间(定义于 httplib.h),让你按块(chunk)读取数据。
客户端:stream::Get逐块消费
httplib::Client cli("http://localhost:11434"); auto result = httplib::stream::Get(cli, "/api/generate"); if (result) { while (result.next()) { std::cout.write(result.data(), result.size()); } }stream::Result对象(httplib.h)封装了流式句柄,除next()/data()/size()外,还提供:
is_valid()/operator bool():判断响应是否有效;status()、headers()、get_header_value():读取响应状态码与响应头;error()/read_error()/has_read_error():区分连接错误与读取过程中的错误;read_all():在需要时仍可一次性读完整响应。
stream::Get支持多个重载,可携带Headers、Params,并可通过最后一个参数指定chunk_size(默认 8192 字节)。除 GET 外,stream::Post、stream::Put、stream::Patch、stream::Delete、stream::Head、stream::Options同样可用(httplib.h),覆盖各类带请求体的流式场景。
客户端:content_receiver回调
也可以把回调直接传给Get(),该方式配合 Keep-Alive 使用效果更佳:
httplib::Client cli("http://localhost:8080"); cli.Get("/stream", [](const char *data, size_t len) { std::cout.write(data, len); return true; // 返回 false 可提前终止接收 });服务端:两种内容提供者
服务端通过Response::set_content_provider()与Response::set_chunked_content_provider()(httplib.h)支持流式响应。两者的选择原则是:知道内容总长度用前者(设置Content-Length),不知道长度用后者(使用 Chunked Transfer Encoding)。
// 已知大小:设置 Content-Length svr.Get("/file", [](const auto &, auto &res) { auto size = get_file_size("large.bin"); res.set_content_provider(size, "application/octet-stream", [](size_t offset, size_t length, httplib::DataSink &sink) { // 发送从 'offset' 开始的 'length' 字节 return true; }); }); // 未知大小:Chunked Transfer Encoding svr.Get("/stream", [](const auto &, auto &res) { res.set_chunked_content_provider("text/plain", [](size_t offset, httplib::DataSink &sink) { sink.write("chunk\n", 6); return true; // 返回 false 表示发送完成 }); });ContentProvider的本质是std::function<bool(size_t offset, size_t length, DataSink &sink)>(httplib.h),DataSink还支持sink.done()、sink.is_writable()以及写入 trailer 头。两个方法都可附带可选的ContentProviderResourceReleaser回调,在流式传输结束或出错时释放资源。
大文件上传:make_file_provider
上传大文件时,make_file_provider()(httplib.h)按 8192 字节缓冲区流式读取文件,而不是把整个文件载入内存:
httplib::Client cli("http://localhost:8080"); auto res = cli.Post("/upload", {}, {}, { httplib::make_file_provider("file", "/path/to/large-file.zip") });该函数返回FormDataProvider,支持可选的filename与content_type参数;其底层 provider 从指定offset继续读取文件直到 EOF 并调用sink.done(),天然适配断点续传式的分块上传。更完整的文件上传方案可参考 Cookbook 中的 c07-multipart-upload 与 c09-chunked-upload。
Server-Sent Events:带自动重连的 SSE 客户端
cpp-httplib 提供了开箱即用的 SSE 客户端httplib::sse::SSEClient(httplib.h),支持基于Last-Event-ID的自动重连与断点续传:
httplib::Client cli("http://localhost:8080"); httplib::sse::SSEClient sse(cli, "/events"); sse.on_message([](const httplib::sse::SSEMessage &msg) { std::cout << msg.event << ": " << msg.data << std::endl; }); sse.start(); // 阻塞运行,内部自动重连SSEMessage(httplib.h)包含event(事件类型,默认"message")、data(事件载荷)和id(用于Last-Event-ID头)。除了on_message全局回调,还可以为每种事件类型单独注册处理器:
sse.on_event("update", [](const httplib::sse::SSEMessage &msg) { // 仅处理 "update" 事件 });SSEClient 还提供一套完整的事件循环控制 API:
on_open(OpenHandler)/on_error(ErrorHandler):连接建立与出错回调;set_reconnect_interval(int ms):重连间隔,默认 3000ms;set_max_reconnect_attempts(int n):最大重连次数,默认 0 表示无限重连;is_connected()/last_event_id():查询连接状态与当前事件 ID;start():阻塞式运行;start_async():后台线程非阻塞运行;stop():线程安全地停止;set_headers(...):线程安全地更新请求头。
服务端的 SSE 实现可参考 README-sse.md 以及 Cookbook 中的 e01-sse-server、e02-sse-event-names、e03-sse-reconnect 与 e04-sse-client。
认证:Basic / Bearer Token / Digest
客户端内置了三种常用认证方式的助手方法:
httplib::Client cli("https://api.example.com"); cli.set_basic_auth("user", "password"); cli.set_bearer_token_auth("my-token");set_basic_auth():在请求头写入Authorization: Basic base64(user:pass);set_bearer_token_auth():写入Authorization: Bearer <token>;- Digest 认证:通过
set_digest_auth()使用,适用于需要摘要式质询-响应流程的服务端。
服务端侧对应的验证与转发技巧可参考 Cookbook 的 c05-basic-auth 与 c06-bearer-token。
压缩:gzip / Brotli / Zstandard
cpp-httplib 支持 gzip、Brotli 与 Zstandard 三种压缩/解压算法,编译时通过宏启用,对应关系如下:
| 算法 | 编译宏 | | -- | -- | | gzip |CPPHTTPLIB_ZLIB_SUPPORT| | Brotli |CPPHTTPLIB_BROTLI_SUPPORT| | Zstandard |CPPHTTPLIB_ZSTD_SUPPORT|
客户端使用方法:
httplib::Client cli("https://example.com"); cli.set_compress(true); // 压缩请求体 cli.set_decompress(true); // 解压响应体其中 gzip 依赖 zlib(CPPHTTPLIB_ZLIB_SUPPORT),Brotli 与 Zstandard 分别依赖对应的官方库;cmake 构建时可通过cmake/FindBrotli.cmake等模块自动探测依赖。更多细节见 Cookbook 的 c15-compression。
代理:HTTP 代理连接
客户端可以经由 HTTP 代理访问目标服务器:
httplib::Client cli("https://example.com"); cli.set_proxy("proxy.example.com", 8080); cli.set_proxy_basic_auth("user", "password");set_proxy()指定代理主机与端口,set_proxy_basic_auth()提供代理的 Basic 认证凭据。仓库的 test/proxy 目录提供了基于 squid 的完整代理测试环境(docker-compose.yml、basic_squid.conf),test_proxy.cc 给出了可复现的验证代码;Cookbook 的 c16-proxy 有更详细讲解。
超时:连接 / 读 / 写独立配置
客户端可以分别设置连接、读、写超时:
httplib::Client cli("https://example.com"); cli.set_connection_timeout(5, 0); // 5 秒 cli.set_read_timeout(10, 0); // 10 秒 cli.set_write_timeout(10, 0); // 10 秒每个方法接收(秒, 微秒)两个参数。此外还可通过set_read_timeout配合流式读取实现超时后的断线处理;超时相关的错误码与处理方式详见 Cookbook 的 c12-timeouts、c13-max-timeout 与 c17-error-codes。
Keep-Alive:复用 TCP 连接
对同一服务器发起多次请求时,开启 Keep-Alive 复用 TCP 连接,避免反复握手:
httplib::Client cli("https://example.com"); cli.set_keep_alive(true);Keep-Alive 下连接可跨多个请求复用,配合前文content_receiver回调的流式读取效果最佳。详细说明见 c14-keep-alive。
服务端中间件:预处理、后处理与异常处理
pre-routing 与 post-routing 钩子
你可以在路由处理前后插入自定义逻辑:
svr.set_pre_routing_handler([](const auto &req, auto &res) { // 在每个请求处理前执行 return httplib::Server::HandlerResponse::Unhandled; // 继续正常路由 }); svr.set_post_routing_handler([](const auto &req, auto &res) { // 响应发送后执行 res.set_header("X-Server", "cpp-httplib"); });set_pre_routing_handler返回HandlerResponse枚举:Unhandled表示继续常规路由,Handled表示由中间件直接终结本次请求(此时 res 已被中间件填好)。set_post_routing_handler在响应发出后运行,适合统一追加响应头。两者更深入的用法见 Cookbook 的 s09-pre-routing 与 s10-post-routing。
通过res.user_data在中间件与处理器间传数据
Response::user_data(httplib.h)是预路由/预请求处理器写入、路由处理器读取的任意数据容器,非常适合共享解析后的认证令牌等上下文:
svr.set_pre_routing_handler([](const auto &req, auto &res) { res.user_data.set("auth_user", std::string("alice")); return httplib::Server::HandlerResponse::Unhandled; }); svr.Get("/me", [](const auto &req, auto &res) { auto *user = res.user_data.get<std::string>("auth_user"); res.set_content("Hello, " + *user, "text/plain"); });注意set_pre_request_handler与之的区别:它在路由匹配之前运行,连 WebSocket 路由也适用(见 s11-pre-request 与 s12-user-data)。
自定义错误与异常处理器
svr.set_error_handler([](const auto &req, auto &res) { res.set_content("Custom Error Page", "text/html"); }); svr.set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) { res.status = 500; res.set_content("Internal Server Error", "text/plain"); });set_error_handler接管所有错误响应(404、405 等)的默认输出;set_exception_handler捕获处理器中抛出的异常并统一转换为 500 响应。两者详见 s13-error-handler 与 s14-exception-handler。
日志:服务端与客户端均可设置
服务端通过set_logger记录每个请求的方法、路径与状态码:
svr.set_logger([](const auto &req, const auto &res) { std::cout << req.method << " " << req.path << " " << res.status << std::endl; });req中还包含remote_addr、header等信息可供记录。客户端同样支持set_logger,详见 s15-server-logger 与 c19-client-logger。
Unix Domain Socket:同机进程通信
除 TCP 外,cpp-httplib 还支持 Unix Domain Socket,适合同机进程间通信(IPC):
// 服务端 httplib::Server svr; svr.set_address_family(AF_UNIX); svr.listen("/tmp/httplib.sock", 0);// 客户端 httplib::Client cli("http://localhost"); cli.set_address_family(AF_UNIX); cli.set_hostname_addr_map({{"localhost", "/tmp/httplib.sock"}}); auto res = cli.Get("/");服务端把地址族设为AF_UNIX并在套接字路径上监听;客户端同样设置AF_UNIX,再通过set_hostname_addr_map把localhost映射到套接字路径,从而让常规的 URL 写法生效。完整示例见 Cookbook 的 s22-unix-socket。
继续深入:官方资源与专题文档
Tour 到此结束,但 cpp-httplib 的探索才刚刚开始。下面这些资源可以帮助你继续深入:
- Cookbook —— 面向常见场景的配方集合,本篇提到的每个特性在 cookbook 中都有对应的分步讲解(路径参数、JSON、静态文件、TLS、WebSocket、SSE、流式响应等);
- README.md —— 完整 API 参考手册;
- README-sse.md —— SSE 的使用指南;
- README-stream.md —— Streaming API 的使用指南;
- README-websocket.md —— WebSocket 服务端与客户端的使用指南。
仓库中还提供了大量可直接运行的示例与测试:example/目录下有server.cc、client.cc、ssecli.cc、ssesvr.cc、wsecho.cc、upload.cc等完整程序,test/test.cc覆盖了上述绝大多数特性的单元测试,docs-src/pages/en/llm-app/则展示了如何用 cpp-httplib 搭建 LLM 应用的 REST API 与 SSE 流式接口。把这些代码与本文的功能速览对照阅读,你就能快速把 cpp-httplib 的进阶能力落地到自己的项目中。
- 后端
- 网络
【免费下载链接】cpp-httplib
A C++ header-only HTTP/HTTPS server and client library
相关推荐
cpp-httplib 的 SSE 客户端:用 httplib::sse::SSEClient 消费 Server-Sent Events 事件流
cpp httplib 的 SSE 客户端:用 httplib::sse::SSEClient 消费 Server Sent Events 事件流 cpp ht
后端网络从0到1:在Electron应用中实现专业级文件压缩与解压缩功能
从0到1:在Electron应用中实现专业级文件压缩与解压缩功能 引言:为什么Electron应用需要可靠的文件压缩方案? 你是否曾在开发Electron应用时
桌面应用示例工程cpp-httplib中的全局超时功能实现解析
cpp httplib中的全局超时功能实现解析 背景介绍 在HTTP客户端开发中,超时控制是一个至关重要的功能。cpp httplib作为一个轻量级的C++ H
后端网络
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考