Add Cookbook S01-S22 (draft)

This commit is contained in:
yhirose
2026-04-10 18:47:42 -04:00
parent 61e533ddc5
commit 361b753f19
45 changed files with 2562 additions and 44 deletions

View File

@@ -0,0 +1,71 @@
---
title: "S07. マルチパートデータをストリーミングで受け取る"
order: 26
status: "draft"
---
大きなファイルをアップロードするハンドラを普通に書くと、`req.body`にリクエスト全体が載ってしまいメモリを圧迫します。`HandlerWithContentReader`を使うと、ボディをチャンクごとに受け取れます。
## 基本の使い方
```cpp
svr.Post("/upload",
[](const httplib::Request &req, httplib::Response &res,
const httplib::ContentReader &content_reader) {
if (req.is_multipart_form_data()) {
content_reader(
// 各パートのヘッダー
[&](const httplib::FormData &file) {
std::cout << "name: " << file.name
<< ", filename: " << file.filename << std::endl;
return true;
},
// 各パートのボディ(複数回呼ばれる)
[&](const char *data, size_t len) {
// ここでファイルに書き出すなど
return true;
});
} else {
// 普通のリクエストボディ
content_reader([&](const char *data, size_t len) {
return true;
});
}
res.set_content("ok", "text/plain");
});
```
`content_reader`は2通りの呼び方ができます。マルチパートのときは2つのコールバックヘッダー用とデータ用を渡し、そうでないときは1つのコールバックだけを渡します。
## ファイルに直接書き出す
大きなファイルをそのままディスクに書き出す例です。
```cpp
svr.Post("/upload",
[](const httplib::Request &req, httplib::Response &res,
const httplib::ContentReader &content_reader) {
std::ofstream ofs;
content_reader(
[&](const httplib::FormData &file) {
if (!file.filename.empty()) {
ofs.open("uploads/" + file.filename, std::ios::binary);
}
return static_cast<bool>(ofs);
},
[&](const char *data, size_t len) {
ofs.write(data, len);
return static_cast<bool>(ofs);
});
res.set_content("uploaded", "text/plain");
});
```
メモリには常に小さなチャンクしか載らないので、ギガバイト級のファイルでも扱えます。
> **Warning:** `HandlerWithContentReader`を使うと、`req.body`は**空のまま**です。ボディはコールバック内で自分で処理してください。
> クライアント側でマルチパートを送る方法はC07. ファイルをマルチパートフォームとしてアップロードするを参照してください。