Files
cpp-httplib/docs-src/pages/ja/tour/03-basic-server.md
yhirose 885ed54b10 Unify spacing and wording in the Japanese docs pages
Drop the spaces between Japanese text and inline code or alphanumerics
in the tour and the few other pages that still had them, and reword
sentences that read awkwardly. The client compression page now lists
Zstd alongside zlib and Brotli.
2026-10-08 20:39:13 -04:00

9.8 KiB

title, order
title order
Basic Server 3

前章ではクライアントからリクエストを送りました。そのとき、テスト用サーバーを用意しましたね。この章では、あのサーバーの仕組みをひとつずつ紐解いていきます。

サーバーの起動

ルーティングを登録したら、最後にsvr.listen()を呼んでサーバーを起動します。

svr.listen("0.0.0.0", 8080);

第1引数はホスト、第2引数はポート番号です。"0.0.0.0"を指定すると、すべてのネットワークインターフェースでリクエストを受け付けます。自分のマシンからのアクセスだけに限定したいときは"127.0.0.1"を使います。

listen()はブロッキング呼び出しです。サーバーが停止するまで、この行から先には進みません。ターミナルでCtrl+Cを押すか、別スレッドからsvr.stop()を呼ぶまでサーバーは動き続けます。

ルーティング

サーバーの核になるのは「ルーティング」です。どのURLに、どのHTTPメソッドでアクセスされたら、何をするか。それを登録する仕組みです。

httplib::Server svr;

svr.Get("/hi", [](const httplib::Request &req, httplib::Response &res) {
    res.set_content("Hello!", "text/plain");
});

svr.Get()は、GETリクエストに対するハンドラーを登録します。第1引数がパス、第2引数がハンドラー関数です。/hiにGETリクエストが来たら、このラムダが呼ばれます。

HTTPメソッドごとにメソッドが用意されています。

svr.Get("/path",    handler);  // GET
svr.Post("/path",   handler);  // POST
svr.Put("/path",    handler);  // PUT
svr.Delete("/path", handler);  // DELETE

ハンドラーのシグネチャは(const httplib::Request &req, httplib::Response &res)です。autoを使って短く書くこともできます。

svr.Get("/hi", [](const auto &req, auto &res) {
    res.set_content("Hello!", "text/plain");
});

パスが一致したときだけハンドラーが呼ばれます。登録されていないパスにアクセスすると、自動的に404が返ります。

リクエストオブジェクト

ハンドラーの第1引数reqから、クライアントが送ってきた情報を読み取れます。

ボディ

req.bodyでリクエストボディを取得できます。型はstd::stringです。

svr.Post("/post", [](const auto &req, auto &res) {
    // クライアントが送ったボディをそのまま返す
    res.set_content(req.body, "text/plain");
});

ヘッダー

req.get_header_value()でリクエストヘッダーの値を取得できます。

svr.Get("/check", [](const auto &req, auto &res) {
    auto auth = req.get_header_value("Authorization");
    res.set_content("Auth: " + auth, "text/plain");
});

クエリパラメーターとフォームデータ

req.get_param_value()でパラメーターを取得できます。GETのクエリパラメーターと、POSTのフォームデータの両方に使えます。

svr.Get("/search", [](const auto &req, auto &res) {
    auto q = req.get_param_value("q");
    res.set_content("Query: " + q, "text/plain");
});

/search?q=cpp-httplibにアクセスすると、qの値は"cpp-httplib"になります。

すべてのパラメーターをループで処理したいときは、req.paramsを使います。

svr.Post("/submit", [](const auto &req, auto &res) {
    std::string result;
    for (auto &[key, val] : req.params) {
        result += key + " = " + val + "\n";
    }
    res.set_content(result, "text/plain");
});

ファイルアップロード

マルチパートフォームでアップロードされたファイルは、req.form.get_file()で取得します。

svr.Post("/upload", [](const auto &req, auto &res) {
    auto f = req.form.get_file("file");
    auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
    res.set_content(content, "text/plain");
});

f.filenameでファイル名、f.contentでファイルの中身にアクセスできます。

パスパラメーター

URLの一部を変数として受け取りたいことがあります。たとえば/users/42の42を取得したい場合です。:param記法を使うと、URLの一部をキャプチャできます。

svr.Get("/users/:id", [](const auto &req, auto &res) {
    auto id = req.path_params.at("id");
    res.set_content("User ID: " + id, "text/plain");
});

/users/42にアクセスすると、req.path_params.at("id")は"42"を返します。/users/100なら"100"です。

複数のパスパラメーターも使えます。

svr.Get("/users/:user_id/posts/:post_id", [](const auto &req, auto &res) {
    auto user_id = req.path_params.at("user_id");
    auto post_id = req.path_params.at("post_id");
    res.set_content("User: " + user_id + ", Post: " + post_id, "text/plain");
});

正規表現パターン

:paramの代わりに正規表現をパスに書くこともできます。キャプチャグループの値はreq.matchesで取得します。型はstd::smatchです。

// 数字のみのIDを受け付ける
svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
    auto id = req.matches[1];  // 最初のキャプチャグループ
    res.set_content("File ID: " + std::string(id), "text/plain");
});

/files/42にはマッチしますが、/files/abcにはマッチしません。入力値を絞り込みたいときに便利です。

レスポンスの組み立て

ハンドラーの第2引数resを使って、クライアントに返すレスポンスを組み立てます。

ボディとContent-Type

res.set_content()でボディとContent-Typeを設定します。これだけでステータスコード200のレスポンスが返ります。

svr.Get("/hi", [](const auto &req, auto &res) {
    res.set_content("Hello!", "text/plain");
});

ステータスコード

ステータスコードを変えたいときは、res.statusに代入します。

svr.Get("/not-found", [](const auto &req, auto &res) {
    res.status = 404;
    res.set_content("Not found", "text/plain");
});

レスポンスヘッダー

res.set_header()でレスポンスヘッダーを追加できます。

svr.Get("/with-header", [](const auto &req, auto &res) {
    res.set_header("X-Custom", "my-value");
    res.set_content("Hello!", "text/plain");
});

前章のサーバーを読み解く

ここまでの知識を使って、前章で用意したテスト用サーバーを改めて見てみましょう。

GET /hi

svr.Get("/hi", [](const auto &, auto &res) {
    res.set_content("Hello!", "text/plain");
});

最もシンプルなハンドラーです。リクエストの情報は使わないので、reqの変数名を省略しています。"Hello!"というテキストをそのまま返します。

svr.Get("/search", [](const auto &req, auto &res) {
    auto q = req.get_param_value("q");
    res.set_content("Query: " + q, "text/plain");
});

req.get_param_value("q")でクエリパラメーターqの値を取り出します。/search?q=cpp-httplibなら、レスポンスは"Query: cpp-httplib"になります。

POST /post

svr.Post("/post", [](const auto &req, auto &res) {
    res.set_content(req.body, "text/plain");
});

クライアントが送ったリクエストボディを、そのままレスポンスとして返すエコーサーバーです。req.bodyにボディが丸ごと入っています。

POST /submit

svr.Post("/submit", [](const auto &req, auto &res) {
    std::string result;
    for (auto &[key, val] : req.params) {
        result += key + " = " + val + "\n";
    }
    res.set_content(result, "text/plain");
});

フォームデータとして送られたキーと値のペアを、req.paramsでループ処理しています。構造化束縛auto &[key, val]を使って、各ペアを取り出しています。

POST /upload

svr.Post("/upload", [](const auto &req, auto &res) {
    auto f = req.form.get_file("file");
    auto content = f.filename + " (" + std::to_string(f.content.size()) + " bytes)";
    res.set_content(content, "text/plain");
});

マルチパートフォームで送られたファイルを受け取ります。req.form.get_file("file")で"file"という名前のフィールドを取得し、f.filenameとf.content.size()でファイル名とサイズを返しています。

GET /users/:id

svr.Get("/users/:id", [](const auto &req, auto &res) {
    auto id = req.path_params.at("id");
    res.set_content("User ID: " + id, "text/plain");
});

:idの部分がパスパラメーターです。req.path_params.at("id")で値を取り出しています。/users/42なら"42"、/users/aliceなら"alice"が得られます。

GET /files/(\d+)

svr.Get(R"(/files/(\d+))", [](const auto &req, auto &res) {
    auto id = req.matches[1];
    res.set_content("File ID: " + std::string(id), "text/plain");
});

正規表現(\d+)で数字だけのIDにマッチします。/files/42にはマッチしますが、/files/abcは404になります。req.matches[1]で最初のキャプチャグループの値を取得しています。

次のステップ

サーバーの基本がわかりましたね。ルーティング、リクエストの読み取り、レスポンスの組み立て。これだけで、十分に実用的なAPIサーバーが作れます。

次は、静的ファイルの配信を見てみましょう。HTMLやCSSを配信するサーバーを作ります。

次: Static File Server