尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

cpp-httplib 客户端实战:获取响应体与使用 ContentReceiver 流式保存大文件

cpp-httplib 客户端实战:获取响应体与使用 ContentReceiver 流式保存大文件 后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载导读在 cpp-httplib 中httplib::Client的Get()调用会返回一个封装了 HTTP 响应的Result对象其中res-body就是一个可直接使用的std::string。本篇 cookbook 指南围绕如何获取响应体、如何把响应保存到文件展开既覆盖一次性读入内存的简单用法也深入讲解借助ContentReceiver回调分块写入磁盘、用ResponseHandler在下载前检查响应头、以及配合进度回调实现取消下载等实战方案。读完本文你将能根据响应大小正确选择内存读取与流式落盘两种模式并掌握 cpp-httplib 客户端响应处理的核心回调体系。1. 准备header-only 客户端的最小用法cpp-httplib 是 header-only 的库客户端代码只需要包含根目录下的 httplib.h 即可无需链接任何库#include httplib.h #include iostream int main() { httplib::Client cli(http://localhost:8080); auto res cli.Get(/hello); if (res res-status 200) { std::cout res-body std::endl; } }以本仓库根目录为当前目录编译header-only 实现C11 即可Unix 系平台通常需要链接 pthreadg -stdc11 -pthread main.cpp -o client仓库中的 example/client.cc 给出了同款的最小用法cli.Get(/hi)后依次读取res-status、res-get_header_value(Content-Type)与res-body。2. 把整个响应体作为字符串获取最简单的方式是直接访问res-bodyhttplib::Client cli(http://localhost:8080); auto res cli.Get(/hello); if (res res-status 200) { std::cout res-body std::endl; }res-body的类型是std::string见 httplib.h 中struct Response的定义拿到手就可以直接使用解析 JSON 时可直接传给 nlohmann/json 这类库返回给上层业务时也无需任何转换。从源码结构看Get()返回的是class Resulthttplib.h它同时封装了响应与错误信息operator bool()当且仅当内部持有有效的Response时返回trueres-statusHTTP 状态码默认值为 -1尚未解析出状态行时为该值res-body、res-headers、res-version、res-reason响应正文、响应头、HTTP 版本与状态文本res.error()enum class Errorhttplib.h配合httplib::to_string(res.error())httplib.h可得到可读的错误描述。2.1 区分连接错误与HTTP 错误判断res本身是否为真与判断res-status是两件独立的事这一模型在 tour/02-basic-client.md 中有完整示例连接层错误服务器不可达连接被拒、超时、TLS 失败等时res为假此时应调用res.error()查看具体原因HTTP 层错误服务器正常返回了 404、500 等状态码时res为真但需要检查res-status才能发现业务失败。推荐的完整检查写法auto res cli.Get(/hello); if (!res) { std::cerr Connection error: httplib::to_string(res.error()) std::endl; return 1; } if (res-status ! 200) { std::cerr HTTP error: res-status std::endl; return 1; } std::cout res-body std::endl;3. 注意res-body会把整个响应加载进内存直接读res-body虽然方便但有一个不可忽视的前提——整个响应体会一次性加载到内存中。对于普通 API 返回的 JSON、HTML 这类小响应完全没问题但如果用同样的方式去抓取一个 GB 级别的文件内存会被整份文件占据既不经济也可能导致 OOM。Warning:If you fetch a large file withres-body, it all goes into memory. For large downloads, use aContentReceiveras shown below.因此判断依据很简单响应体积小、后续需要整体处理 → 用res-body响应体积大、目标是落盘 → 用ContentReceiver流式接收。4. 使用 ContentReceiver 分块下载并直接写入文件对于大文件下载cpp-httplib 提供ContentReceiver回调机制数据到达后按分块交给你的回调每一块处理完即可丢弃不必等整个响应体收齐。httplib::Client cli(http://localhost:8080); std::ofstream ofs(output.bin, std::ios::binary); if (!ofs) { std::cerr Failed to open file std::endl; return 1; } auto res cli.Get(/large-file, { ofs.write(data, len); return static_castbool(ofs); });要点说明回调签名bool(const char *data, size_t data_length)与源码中using ContentReceiver std::functionbool(const char *data, size_t data_length)httplib.h一致分块落盘回调被调用多少次取决于传输分块每个分块直接ofs.write(data, len)写入整份文件不需要先在内存里拼完整二进制安全目标文件务必以std::ios::binary打开避免平台相关的换行转换破坏数据回调返回值即是否继续返回false会立即中止本次下载。上面的例子中一旦ofs.write使流进入失败状态static_castbool(ofs)为false下载自动停止不会继续把数据写进一个已经出错的流。4.1Get()的多个重载与参数组合从 httplib.h客户端侧与 httplib.h流式客户端侧可以看到Get()提供了一系列重载可以按需组合Get(path)最简形式响应整体进内存通过res-body读取Get(path, ContentReceiver)正文以分块方式交给回调本节用法Get(path, ResponseHandler, ContentReceiver)先回调响应头再分块接收正文下一节Get(path, Headers)/Get(path, Params)/Get(path, Params, Headers)携带自定义请求头或查询参数上述任意形式后还可追加DownloadProgress进度回调见第 6 节。5. 下载前检查响应头ResponseHandler ContentReceiver 组合很多时候我们需要先知道这个文件有多大、是什么类型再决定是否下载。cpp-httplib 允许在正文接收之前插入一个ResponseHandlerauto res cli.Get(/large-file, [](const httplib::Response res) { auto len res.get_header_value(Content-Length); std::cout Size: len std::endl; return true; // return false to skip the download }, { ofs.write(data, len); return static_castbool(ofs); });关键语义执行时机ResponseHandler在响应头到达之后、正文开始接收之前被调用。源码中using ResponseHandler std::functionbool(const Response response)httplib.h读取头部通过res.get_header_value(Content-Length)httplib.h读取指定头若关心数值比较还可使用get_header_value_u64(key, def, id)httplib.h它返回size_t并支持默认值更适合做剩余空间是否够这类数值判断返回false跳过下载ResponseHandler返回false时本次下载被整体跳过。典型场景是Content-Length 超过磁盘剩余空间、或者响应 Content-Type 不符合预期时提前放弃省去无谓的流量消耗。实际应用时可以先在ResponseHandler里完成长度/类型检查把是否继续的决定权交给返回值只有通过检查的响应才会进入ContentReceiver逐块落盘。6. 进阶边下载边显示进度并可随时取消当同时需要流式写文件和进度展示时把ContentReceiver与DownloadProgress一起传入即可httplib::Client cli(http://localhost:8080); auto res cli.Get(/large-file, [](size_t current, size_t total) { auto percent (total 0) ? (current * 100 / total) : 0; std::cout \rDownloading: percent % ( current / total ) std::flush; return true; // return false to abort }, { ofs.write(data, len); return static_castbool(ofs); });回调签名DownloadProgress定义为std::functionbool(size_t current, size_t total)httplib.htotal的来源来自响应头Content-Length。若服务器未发送该头例如 chunked 传输total可能为 0此时无法计算百分比退化为只显示已接收字节数取消下载进度回调返回false即可中止传输。UI 场景下常用一个std::atomicbool标志位配合取消按钮下一次进度 tick 到来时返回!cancelled.load()即可停止具体示例见 C11. Use the progress callback。上传方向同理Post()/Put()的最后一个参数可传入UploadProgress进度语义完全一致。7. 本节要点速查场景推荐方式内存特征小响应API JSON / HTMLcli.Get(path)后读res-body整份进内存方便直接使用大文件下载cli.Get(path, ContentReceiver)分块回调逐块落盘内存占用低下载前先校验大小/类型cli.Get(path, ResponseHandler, ContentReceiver)ResponseHandler返回false可整体跳过大文件 进度/取消ContentReceiverDownloadProgress同时传入分块处理进度回调控制中止无论采用哪种形式都应先判断res是否为真连接层是否成功再判断res-statusHTTP 层是否成功最后按需消费res-body或回调数据。参考与延伸阅读本文关联文档C01. Get the response body / save to a file进度回调与取消下载的完整示例C11. Use the progress callback客户端基础用法查询参数、请求头、POST、错误处理Basic Client核心实现Result与Response定义见 httplib.h 和 httplib.hGet()全部重载见 httplib.h可运行示例example/client.cc赞分享后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载相关推荐OpenStatus Docker 部署完全指南从快速启动到生产级自托管OpenStatus Docker 部署完全指南从快速启动到生产级自托管 OpenStatus 是一个开源的状态页与可用性监控平台支持通过代码YAML/T后端网络cpp-httplib 流式接收响应用 ContentReceiver 逐块处理大文件、NDJSON 与日志流cpp httplib 流式接收响应用 ContentReceiver 逐块处理大文件、NDJSON 与日志流 本指南聚焦 cpp httplib 客户端侧“后端网络SeaTunnel Airtable Source Connector 使用指南配置详解、限流机制与实战示例SeaTunnel Airtable Source Connector 使用指南配置详解、限流机制与实战示例 Airtable Source Connecto后端网络创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表