mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-09 21:03:18 +00:00
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.
267 lines
7.9 KiB
Markdown
267 lines
7.9 KiB
Markdown
---
|
||
title: "Basic Client"
|
||
order: 2
|
||
---
|
||
|
||
cpp-httplibはサーバーだけでなく、HTTPクライアント機能も備えています。`httplib::Client`を使って、GETやPOSTリクエストを送ってみましょう。
|
||
|
||
## テスト用サーバーの準備
|
||
|
||
クライアントの動作を確認するために、リクエストを受け付けるサーバーを用意します。次のコードを保存し、前章と同じ手順でコンパイル・実行してください。サーバーの詳しい解説は次章で行います。
|
||
|
||
```cpp
|
||
#include "httplib.h"
|
||
#include <iostream>
|
||
|
||
int main() {
|
||
httplib::Server svr;
|
||
|
||
svr.Get("/hi", [](const auto &, auto &res) {
|
||
res.set_content("Hello!", "text/plain");
|
||
});
|
||
|
||
svr.Get("/search", [](const auto &req, auto &res) {
|
||
auto q = req.get_param_value("q");
|
||
res.set_content("Query: " + q, "text/plain");
|
||
});
|
||
|
||
svr.Post("/post", [](const auto &req, auto &res) {
|
||
res.set_content(req.body, "text/plain");
|
||
});
|
||
|
||
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");
|
||
});
|
||
|
||
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");
|
||
});
|
||
|
||
svr.Get("/users/:id", [](const auto &req, auto &res) {
|
||
auto id = req.path_params.at("id");
|
||
res.set_content("User ID: " + id, "text/plain");
|
||
});
|
||
|
||
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");
|
||
});
|
||
|
||
std::cout << "Listening on port 8080..." << std::endl;
|
||
svr.listen("0.0.0.0", 8080);
|
||
}
|
||
```
|
||
|
||
## GETリクエスト
|
||
|
||
サーバーが起動したら、別のターミナルを開いて試してみましょう。まず、最もシンプルなGETリクエストです。
|
||
|
||
```cpp
|
||
#include "httplib.h"
|
||
#include <iostream>
|
||
|
||
int main() {
|
||
httplib::Client cli("http://localhost:8080");
|
||
|
||
auto res = cli.Get("/hi");
|
||
if (res) {
|
||
std::cout << res->status << std::endl; // 200
|
||
std::cout << res->body << std::endl; // Hello!
|
||
}
|
||
}
|
||
```
|
||
|
||
`httplib::Client`のコンストラクターにサーバーのアドレスを渡し、`Get()`でリクエストを送ります。戻り値の`res`からステータスコードやボディを取得できます。
|
||
|
||
対応する`curl`コマンドはこうなります。
|
||
|
||
```sh
|
||
curl http://localhost:8080/hi
|
||
# Hello!
|
||
```
|
||
|
||
## レスポンスの確認
|
||
|
||
レスポンスには、ステータスコードとボディ以外にもヘッダー情報が含まれています。
|
||
|
||
```cpp
|
||
auto res = cli.Get("/hi");
|
||
if (res) {
|
||
// ステータスコード
|
||
std::cout << res->status << std::endl; // 200
|
||
|
||
// ボディ
|
||
std::cout << res->body << std::endl; // Hello!
|
||
|
||
// ヘッダー
|
||
std::cout << res->get_header_value("Content-Type") << std::endl; // text/plain
|
||
}
|
||
```
|
||
|
||
`res->body`は`std::string`なので、JSONレスポンスをパースしたい場合は[nlohmann/json](https://github.com/nlohmann/json)などのJSONライブラリにそのまま渡せます。
|
||
|
||
## クエリパラメーター
|
||
|
||
GETリクエストにクエリパラメーターを付けるには、URLに直接書くか、`httplib::Params`を使います。
|
||
|
||
```cpp
|
||
auto res = cli.Get("/search", httplib::Params{{"q", "cpp-httplib"}});
|
||
if (res) {
|
||
std::cout << res->body << std::endl; // Query: cpp-httplib
|
||
}
|
||
```
|
||
|
||
`httplib::Params`を使うと、特殊文字のURLエンコードを自動で行ってくれます。
|
||
|
||
```sh
|
||
curl "http://localhost:8080/search?q=cpp-httplib"
|
||
# Query: cpp-httplib
|
||
```
|
||
|
||
## パスパラメーター
|
||
|
||
URLのパスに値を直接埋め込む場合も、クライアント側は特別なAPIは不要です。パスをそのまま`Get()`に渡すだけです。
|
||
|
||
```cpp
|
||
auto res = cli.Get("/users/42");
|
||
if (res) {
|
||
std::cout << res->body << std::endl; // User ID: 42
|
||
}
|
||
```
|
||
|
||
```sh
|
||
curl http://localhost:8080/users/42
|
||
# User ID: 42
|
||
```
|
||
|
||
テスト用サーバーには、正規表現でIDを数字のみに絞った`/files/(\d+)`もあります。
|
||
|
||
```cpp
|
||
auto res = cli.Get("/files/42");
|
||
if (res) {
|
||
std::cout << res->body << std::endl; // File ID: 42
|
||
}
|
||
```
|
||
|
||
```sh
|
||
curl http://localhost:8080/files/42
|
||
# File ID: 42
|
||
```
|
||
|
||
`/files/abc`のように数字以外を渡すと404が返ります。仕組みは次章で解説します。
|
||
|
||
## リクエストヘッダー
|
||
|
||
カスタムHTTPヘッダーを付けるには、`httplib::Headers`を渡します。`Get()`や`Post()`のどちらでも使えます。
|
||
|
||
```cpp
|
||
auto res = cli.Get("/hi", httplib::Headers{
|
||
{"Authorization", "Bearer my-token"}
|
||
});
|
||
```
|
||
|
||
```sh
|
||
curl -H "Authorization: Bearer my-token" http://localhost:8080/hi
|
||
```
|
||
|
||
## POSTリクエスト
|
||
|
||
テキストデータをPOSTしてみましょう。`Post()`の第2引数にボディ、第3引数にContent-Typeを指定します。
|
||
|
||
```cpp
|
||
auto res = cli.Post("/post", "Hello, Server!", "text/plain");
|
||
if (res) {
|
||
std::cout << res->status << std::endl; // 200
|
||
std::cout << res->body << std::endl; // Hello, Server!
|
||
}
|
||
```
|
||
|
||
テスト用サーバーの`/post`はボディをそのまま返すので、送った文字列がそのまま返ってきます。
|
||
|
||
```sh
|
||
curl -X POST -H "Content-Type: text/plain" -d "Hello, Server!" http://localhost:8080/post
|
||
# Hello, Server!
|
||
```
|
||
|
||
## フォームデータの送信
|
||
|
||
HTMLフォームのように、キーと値のペアを送ることもできます。`httplib::Params`を使います。
|
||
|
||
```cpp
|
||
auto res = cli.Post("/submit", httplib::Params{
|
||
{"name", "Alice"},
|
||
{"age", "30"}
|
||
});
|
||
if (res) {
|
||
std::cout << res->body << std::endl;
|
||
// name = Alice
|
||
// age = 30
|
||
}
|
||
```
|
||
|
||
これは`application/x-www-form-urlencoded`形式で送信されます。
|
||
|
||
```sh
|
||
curl -X POST -d "name=Alice&age=30" http://localhost:8080/submit
|
||
```
|
||
|
||
## ファイルのPOST
|
||
|
||
ファイルをアップロードするには、`httplib::UploadFormDataItems`を使ってマルチパートフォームデータとして送信します。
|
||
|
||
```cpp
|
||
auto res = cli.Post("/upload", httplib::UploadFormDataItems{
|
||
{"file", "Hello, File!", "hello.txt", "text/plain"}
|
||
});
|
||
if (res) {
|
||
std::cout << res->body << std::endl; // hello.txt (12 bytes)
|
||
}
|
||
```
|
||
|
||
`UploadFormDataItems`の各要素は`{name, content, filename, content_type}`の4つのフィールドで構成されます。
|
||
|
||
```sh
|
||
curl -F "file=Hello, File!;filename=hello.txt;type=text/plain" http://localhost:8080/upload
|
||
```
|
||
|
||
## エラーハンドリング
|
||
|
||
ネットワーク通信では、サーバーに接続できない場合があります。`res`が有効かどうかを必ず確認しましょう。
|
||
|
||
```cpp
|
||
httplib::Client cli("http://localhost:9999"); // 存在しないポート
|
||
auto res = cli.Get("/hi");
|
||
|
||
if (!res) {
|
||
// 接続エラー
|
||
std::cout << "Error: " << httplib::to_string(res.error()) << std::endl;
|
||
// Error: Could not establish connection
|
||
return 1;
|
||
}
|
||
|
||
// ここに到達すればレスポンスを受信できている
|
||
if (res->status != 200) {
|
||
std::cout << "HTTP Error: " << res->status << std::endl;
|
||
return 1;
|
||
}
|
||
|
||
std::cout << res->body << std::endl;
|
||
```
|
||
|
||
エラーには2つのレベルがあります。
|
||
|
||
- **接続エラー**: サーバーに到達できなかった場合。`res`が偽になり、`res.error()`でエラーの種類を取得できます
|
||
- **HTTPエラー**: サーバーからエラーステータス(404、500など)が返ってきた場合。`res`は真ですが、`res->status`を確認する必要があります
|
||
|
||
## 次のステップ
|
||
|
||
クライアントからリクエストを送る方法がわかりました。次は、サーバー側をもっと詳しく見てみましょう。ルーティングやパスパラメータなど、サーバーの機能を掘り下げます。
|
||
|
||
**次:** [Basic Server](../03-basic-server)
|