1. 程式人生 > >C++ 使用 curl 傳送 json 資料請求

C++ 使用 curl 傳送 json 資料請求

用到的庫:

假設現在 Client 想要獲取 Person 喜歡的語言,需要傳送 Person 的個人資訊到 Server,Server 根據使用者姓名返回他喜歡的語言。

struct Book {
  std::string name;
};

struct Person {
  std::string name;
  int age;
  std::vector<Book> favoriteBooks;
};

struct FavoriteLanguage {
  std::string name;
  std
::vector<std::string> languages; };

這個過程需要三個處理步驟:
- Client 將 Person 資訊轉為 json,並通過 curl 傳送出去
- Server 收到資料後解 json 處理並返回該 Person 喜歡的語言
- Client 收到 Response 後解 json 得到喜歡的語言

Book 轉 json:

void to_json(json &j, const Book &book) {
  j = {
      {"name", book.name}
  };
}

Person 轉 json:

void to_json(json &j, const Person &p) {
  j = {
      {"name", p.name},
      {"age", p.age}
  };
  if (!p.favoriteBooks.empty())
    j.push_back({"books", p.favoriteBooks});
}
Person p{"Aland", 18, books};
json j = p; // Person 轉 json
std::string dump = j.dump();

通過 curl 傳送 http POST 請求,資料為 json 格式。

std::string url = "127.0.0.1:9999/favorbooks";
CURL *curl;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L); // POST
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dump.c_str()); // 要傳送的資料
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); // 處理 response 的回撥函式
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &favor); // 儲存返回的結果

curl_easy_perform(curl);
curl_easy_cleanup(curl);

Client 解析返回的 response:

static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
  size_t realsize = size * nmemb;
  auto j = json::parse(std::string((char *) ptr));
  FavoriteLanguage *favor = (FavoriteLanguage *) userp;
  *favor = j; // json 轉 FavoriteLanguage
  return realsize;
}

json 轉結構體:

void from_json(const json &j, FavoriteLanguage &favor) {
  favor.name = j["name"];
  favor.languages = j["languages"].get<std::vector<std::string>>();
}

解析後的列印結果:

{"age":18,"books":[{"name":"TCP/IP Illustrated, Volume 1"},{"name":"Advanced Programming in the UNIX Environment"}],"name":"Aland"}
{"languages":["C++","Golang","Python"],"name":"Aland"}
Name:Aland
Languages:
  C++
  Golang
  Python

注: 詳細程式碼見 https://github.com/alandtsang/cppdemo/tree/master/src/curljson

遇到的錯誤

could not find to_json() method in T's namespace

這個問題通常是兩點引起的(下列解法對to_jsonfrom_json 都適用):

  • 沒有對要轉換的結構體做 to_json 轉換。
  • 外層結構體做了 to_json 轉換,但是結構體包含的結構體沒有做 to_json 轉換。

參考

C libcurl get output into a string

creating nested json object in c++ using nlohmann json

Unable to locate ‘to_json()’ and ‘from_json()’ methods in the same namespace

Why not also look inside the type for (static) to_json and from_json funtions?