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

资讯详情

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

cpp-httplib 实战:使用 make_file_body() 以原始二进制形式 POST/PUT 文件内容

cpp-httplib 实战:使用 make_file_body() 以原始二进制形式 POST/PUT 文件内容 后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载导读在对接 S3 兼容存储 API、图片上传接口等场景时往往需要把整个文件内容原样作为 HTTP 请求体发送而不是包装成 multipart 表单。cpp-httplib 提供了httplib::make_file_body()它把文件路径解析为「文件大小 ContentProvider」的组合让你通过Post()/Put()直接以Content-Length方式流式上传大文件。读完本文你将掌握该 API 的调用方式、底层读取机制、失败处理要点及其适用边界并能结合仓库源码理解它为何可以做到大文件不占用内存。为什么需要「原始二进制」请求体普通文本或小文件可以用cli.Post(path, body, content_type)直接把std::string作为请求体发送。但有两类需求不适合这种方式请求体必须精确等于文件字节内容不能有多余的分隔符、boundary 或字段头——例如 S3 兼容 API 的PUT /bucket/key上传以及接收原始图片数据的端点文件很大把整个文件读进std::string会带来显著内存开销。multipart 上传见 C07. Upload a file as multipart form data适用于同时携带多个字段或文件而本场景只需要「文件内容直通请求体」。make_file_body()正是为此设计。基本用法#include httplib.h #include iostream int main() { httplib::Client cli(https://storage.example.com); // 返回 (文件大小, ContentProvider) 的组合 auto [size, provider] httplib::make_file_body(backup.tar.gz); if (size 0) { std::cerr Failed to open file std::endl; return 1; } auto res cli.Put(/bucket/backup.tar.gz, size, provider, application/gzip); if (res res-status 200) { std::cout Upload succeeded std::endl; } else { std::cerr Upload failed: httplib::to_string(res.error()) std::endl; } return 0; }要点说明make_file_body()接受文件路径std::string返回std::pairsize_t, ContentProviderfirst是文件字节大小second是内容提供器。将size、provider直接传给Post()或Put()文件内容便作为请求体原样发送。第三个参数是Content-Type例如application/gzip、application/octet-stream、image/jpeg按目标端点要求填写即可。这与仓库 README.md 中的示例用法一致auto [size, provider] httplib::make_file_body(/path/to/data.bin); auto res cli.Post(/upload, size, provider, application/octet-stream);从源码结构看客户端为此提供了若干配套重载例如见 httplib.hResult Post(const std::string path, size_t content_length, ContentProvider content_provider, const std::string content_type, UploadProgress progress nullptr); Result Put(const std::string path, size_t content_length, ContentProvider content_provider, const std::string content_type, UploadProgress progress nullptr);即「显式content_lengthContentProviderContent-Type可选进度回调」这一族 API与make_file_body()的返回类型精确对接。ContentProvider 是如何做到流式读取的ContentProvider在 httplib.h 中定义为一个函数对象using ContentProvider std::functionbool(size_t offset, size_t length, DataSink sink);它接收offset本次要发送的起始偏移和length本次要发送的字节数通过sink.write(buf, n)把数据交出去返回bool表示是否成功。DataSink见 httplib.h封装了write、done、is_writable等回调并提供一个std::ostream os便于以流方式输出。make_file_body()的实现见 httplib.h分两步探测文件大小以std::ios::binary | std::ios::ate打开文件用tellg()取得大小并返回打开失败则返回{0, ContentProvider{}}。构造分块读取的 provider真正的上传阶段provider 每次最多读取8192 字节char buf[8192]并把读到的内容立即交给sink.write()ContentProvider provider filepath - bool { std::ifstream f(filepath, std::ios::binary); if (!f) { return false; } f.seekg(static_caststd::streamoff(offset)); if (!f.good()) { return false; } char buf[8192]; while (length 0) { auto to_read (std::min)(sizeof(buf), length); f.read(buf, static_caststd::streamsize(to_read)); auto n static_castsize_t(f.gcount()); if (n 0) { return false; } if (!sink.write(buf, n)) { return false; } length - n; } return true; };因此无论文件多大同一时刻内存中最多只驻留一个 8 KiB 的缓冲区大文件上传也不会把整个文件载入内存——这正是本 API 相对「整体读入字符串再发送」的核心优势。文件打不开时会发生什么make_file_body()打开文件失败时返回的size为0provider为空函数对象ContentProvider{}。如果忽略检查而直接发送请求体会是垃圾数据必须始终先检查sizeauto [size, provider] httplib::make_file_body(backup.tar.gz); if (size 0) { // 处理文件不存在 / 无权限等情况而不是继续发送 }这一点在测试中有直接佐证。test/test.cc 的MakeFileBodyTest.Basic先写一个 4096 字节的临时文件再make_file_body()后断言fb.first 0随后用cli.Post(/upload, fb.first, fb.second, application/octet-stream)上传服务端收到的req.body与文件内容完全相等验证了「大小 provider」组合端到端的正确性。警告Content-Length 是预先固定下来的make_file_body()在返回前就用tellg()读了一次文件大小这个值随后会作为Content-Length承诺给对端。因此若上传过程中文件被截短provider 读到n 0EOF 提前到来时会返回false传输以失败告终——实现中的注释也明确指出调用方已把测量到的大小作为 Content-Length 发出请求体无法补全时只能像其他错误一样失败见 httplib.h若文件在测量后被写大则发送内容仍以测量时的大小为限。也就是说如果你无法保证上传期间文件大小不变这个 API 就不适合。此时应改用不确定长度的分块传输chunked方案或先在本地固定一份快照再上传。test/test.cc 的MakeFileBodyTest.TruncatedFileMakesTheProviderFail精确复现了这一场景先测量 100 字节的文件随后把文件截短为 10 字节再调用 provider 期望其返回false且写入 sink 的只有 10 字节。而MakeFileBodyTest.WholeFileIsSenttest/test.cc用 9000 字节内容跨多个 8 KiB 读取验证了 provider 能把整个文件完整送出两次测试共同构成了该 API 的边界行为契约。与 multipart 上传如何取舍如果你需要的是「表单字段 文件」的组合或一次携带多个文件应该走 multipart 路线使用httplib::make_file_provider()构造FormDataProviderItems再调用cli.Post(/upload, {}, {}, providers)见 README.md详见 C07. Upload a file as multipart form data。选择依据可以简单归纳为需求推荐 API请求体 单个文件原始字节且有确定的 Content-Lengthmake_file_body()Post()/Put()需要多个字段/文件或字段与文件混合make_file_provider()/FormDataProviderItems multipart文件大小无法预先固定、需要流式分块ContentProviderWithoutLength chunked 上传见 C09. Chunked upload小结httplib::make_file_body(path)返回(size, ContentProvider)配合Post()/Put()即可把文件作为原始二进制请求体发送Content-Type由你指定。底层按 8192 字节分块经DataSink写出超大文件也不会整体驻留内存。文件打不开时返回size 0必须显式检查后再发送。Content-Length 在调用前就已固定上传期间文件大小可能变化时请改用其他方案。多文件/字段场景请回到 multipart 路线C07分块流式场景可参考 C09。赞分享后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载相关推荐cpp-httplib 实战用 make_file_body 将文件作为原始二进制请求体直接上传cpp httplib 实战用 make_file_body 将文件作为原始二进制请求体直接上传 本篇指南围绕 cpp httplib 提供的 make_fi后端网络cpp-httplib 基础客户端实战用 httplib::Client 发送 GET / POST 与文件上传cpp httplib 基础客户端实战用 httplib::Client 发送 GET / POST 与文件上传 cpp httplib 不仅是一个 head后端网络WinUI TabView v2 增强指南TabWidthMode Compact 与 CloseButtonOverlayMode 完全解析WinUI TabView v2 增强指南TabWidthMode Compact 与 CloseButtonOverlayMode 完全解析 导读 本文以微后端网络创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表