Как сохранить результаты curl-запроса в Json::Value?
Проблема в следующем, надо прочитать json файл с сайта и занести его в json::value.
Пытался сделать так
#include <iostream>
#include "curl/curl.h"
#include "json/json.h"
using namespace std;
int main(int argc, char* argv[])
{
Json::Value message;
CURL* req = curl_easy_init();
CURLcode res;
curl_easy_setopt(req, CURLOPT_URL, "ссылка");
curl_easy_setopt(req, CURLOPT_FOLLOWLOCATION, 1L);
message = curl_easy_perform(req);
cout << message;
}
Но почему-то в message ноль. Каким образом в него можно занести данные, полученные с сайта?
Ответы (1 шт):
curl предоставляет возможность зарегистрировать функцию-обработчик, которая будет вызвана при получении очередной порции данных:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onDataReceived);
Функция onDataReceived принимает следующие параметры:
- ptr - указатель на буфер с полученными данными
- size - всегда равен 1 (или в большинстве случаев)
- nmemb - размер буфера
- userdata - см. ниже
Кроме того, необходимо указать буфер, в который будут записаны полученные данные:
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);
, где buf - указатель на буфер, который можно получить в функции onDataReceived приведением userdata к нужному типу.
Небольшой пример:
#include <iostream>
#include <sstream>
#include <string>
#include <curl/curl.h>
#include <json/json.h>
auto onDataReceived(char* ptr, std::size_t size, std::size_t nmemb, void* userdata) -> std::size_t;
constexpr auto k_max_buffer_size = 4096;
auto main() -> int
{
std::string data;
bool request_complete = true;
if (auto curl = curl_easy_init())
{
curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/users/hadley/orgs");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onDataReceived);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Ninja");
if (curl_easy_perform(curl) != CURLE_OK)
{
request_complete = false;
std::cerr << "An error occurred while executing the request" << std::endl;
}
curl_easy_cleanup(curl);
}
if (request_complete)
{
std::istringstream stream { data };
Json::Value json;
stream >> json;
std::cout << json.toStyledString() << std::endl;
}
}
auto onDataReceived(char* ptr, std::size_t size, std::size_t nmemb, void* data) -> std::size_t
{
if (auto str = reinterpret_cast<std::string*>(data))
{
str->append(ptr, nmemb * size);
}
return nmemb * size;
}
Здесь в качестве буфера я использую объект типа std::string, так как мне лень использовать массивы и следить за размером буфера (т.к. мы не знаем заранее, сколько байт нужно для того, чтобы сохранить полученные данные).
Что касается добавления хедера User-Agent - добавил только потому, что при отсутствии последнего данный сервис возвращает ошибку. Если используемый Вами ресурс не требует данного хедера - уберите.
Вывод должен быть примерно следующим:
[
{
"avatar_url" : "https://avatars1.githubusercontent.com/u/423638?v=4",
"description" : "",
"events_url" : "https://api.github.com/orgs/ggobi/events",
"hooks_url" : "https://api.github.com/orgs/ggobi/hooks",
"id" : 423638,
"issues_url" : "https://api.github.com/orgs/ggobi/issues",
"login" : "ggobi",
"members_url" : "https://api.github.com/orgs/ggobi/members{/member}",
"node_id" : "MDEyOk9yZ2FuaXphdGlvbjQyMzYzOA==",
"public_members_url" : "https://api.github.com/orgs/ggobi/public_members{/member}",
"repos_url" : "https://api.github.com/orgs/ggobi/repos",
"url" : "https://api.github.com/orgs/ggobi"
},
...
]