如何在 C 中使用 curl 并解析 JSON 响应

How to use curl in C and parse JSON response

下面的代码编译并打印响应。

我的问题是:作为表示对象的字符串的响应,如何将“res”转换为字符串或直接转换为 JSON 对象?

#include <stdio.h>
#include <curl/curl.h>
#include <json-c/json.h>

int main(int argc, char **argv) {
    CURL *curl;
    CURLcode res;
    curl = curl_easy_init();

    if(curl) {
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
        curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:8080/system/genpass");
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "length: 20");
        headers = curl_slist_append(headers, "numbers: true");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        res = curl_easy_perform(curl);
        printf("%u",res);
    }

    curl_easy_cleanup(curl);
}

您不能简单地将函数的 return 代码转换为字符串。 他们没有任何关系。

相反,您需要直接处理接收到的数据。 为此,您需要注册一个可以处理数据的回调函数。 cURL manual.

中对此进行了描述

示例:

typedef struct {
    unsigned char *buffer;
    size_t len;
    size_t buflen;
} get_request;

#define CHUNK_SIZE 2048

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t realsize = size * nmemb; 
    get_request *req = (get_request *) userdata;

    printf("receive chunk of %zu bytes\n", realsize);

    while (req->buflen < req->len + realsize + 1)
    {
        req->buffer = realloc(req->buffer, req->buflen + CHUNK_SIZE);
        req->buflen += CHUNK_SIZE;
    }
    memcpy(&req->buffer[req->len], ptr, realsize);
    req->len += realsize;
    req->buffer[req->len] = 0;

    return realsize;
}


int main(int argc, char **argv) {
    CURL *curl;
    CURLcode res;
    curl = curl_easy_init();

    get_request req = {.buffer = NULL, .len = 0, .buflen = 0};

    if (curl) {
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "length: 20");
        headers = curl_slist_append(headers, "numbers: true");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        req.buffer = malloc(CHUNK_SIZE);
        req.buflen = CHUNK_SIZE;

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&req);

        res = curl_easy_perform(curl);
        printf("Result = %u\n",res);

        printf("Total received bytes: %zu\n", req.len);
        printf("Received data:/n%s\n", req.buffer);
        free(req.buffer);        
    }

    curl_easy_cleanup(curl);
}

输出:

receive chunk of 1256 bytes
Result = 0
Total received bytes: 1256
Received data:
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

GET请求完成后,您可以访问req->buffer中的数据并解析JSON个对象或任何其他数据。 需要添加错误检查(针对 realloc 等)。

我使用的方法能够处理接收到的任意数量的块中的任意长度的内容。 如果您知道预期内容的长度,则可以使用固定大小的缓冲区。

在我的例子中可以看到,用户数据结构在下载完成后仍然存在,并且在curl_easy_perform return秒后可以导出内容。