【问题标题】:JSON requests in C using libcurl使用 libcurl 在 C 中的 JSON 请求
【发布时间】:2012-08-12 00:36:17
【问题描述】:

我正在使用 C 中的 libcurl 定义一个带有 JSON 请求正文的 PUT 请求。

这就是我的做法:

    sprintf(jsonObj, "\"name\" : \"%s\", \"age\" : \"%s\"", name, age);

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charset: utf-8");

    curl_easy_setopt(curl, CURLOPT_URL, url);

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");

    res = curl_easy_perform(curl);

请求正文是这样到达的:

    { '"name" : "Pedro", "age" : "22"' }

{ ' 开头,' } 结尾。

--- 更多信息 -----

如果我声明此代码

    char* jsonObj = "{ \"name\" : \"Pedro\" , \"age\" : \"22\" }"; 

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charset: utf-8");

    curl_easy_setopt(curl, CURLOPT_URL, url);

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");

    res = curl_easy_perform(curl);

服务器将其作为请求正文接收:

{ '{ "name" : "Pedro" , "age" : "22" }': '' }

我的问题是:

libCurl 是否自动对 Json 请求进行预格式化/编码?

顺便说一句,libCurl 是否有某种方式对 JSON 对象进行编码?

非常感谢!

【问题讨论】:

    标签: c json libcurl


    【解决方案1】:

    首先,让我们注意一些事情。首先,Daniel Stenberg 是正确的(鉴于他编写了代码,我希望他是正确的):libcurl 不会将任何数据附加到您的代码中。我可以使用这个示例程序来演示这一点,它与您的示例类似,但有一些额外的设置/拆卸代码。这是代码的全部:这里没有其他内容:

    #include <curl/curl.h>
    
    int main (int argc, char *argv[]) {
        CURL *curl;
        CURLcode res;
    
        curl_global_init(CURL_GLOBAL_ALL);
        curl = curl_easy_init();
        if (curl == NULL) {
            return 128;
        }
    
        char* jsonObj = "{ \"name\" : \"Pedro\" , \"age\" : \"22\" }";
    
        struct curl_slist *headers = NULL;
        curl_slist_append(headers, "Accept: application/json");
        curl_slist_append(headers, "Content-Type: application/json");
        curl_slist_append(headers, "charset: utf-8");
    
        curl_easy_setopt(curl, CURLOPT_URL, "http://http2bin.org/put");
    
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
    
        res = curl_easy_perform(curl);
    
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return res;
    }
    

    使用 Wireshark 捕获请求的数据包表明这会发出以下 HTTP 请求:

    PUT /put HTTP/1.1
    Host: http2bin.org
    User-Agent: libcrp/0.1
    Accept: */*
    Content-Length: 35
    Content-Type: application/x-www-form-urlencoded
    
    { "name" : "Pedro" , "age" : "22" }
    

    如您所见,这正是您要求发送的 JSON 数据。这里没有多余的数据,没有括号。

    这意味着额外的大括号要么由您的服务器添加,要么由一些中间中间盒添加。我的猜测是您的服务器正在添加它,因为它通过将整个正文视为字符串来强行尝试将任何不是 application/json 正文的正文转换为

    您的服务器不认为这是 JSON 正文的原因被另一个答案封装在这里:您没有正确设置标头。 curl_slist_append 返回一个新的struct curl_slist *,您需要将其分配回您的headers 变量。这意味着您需要更改以下四行:

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charset: utf-8");
    

    这四个:

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Accept: application/json");
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, "charset: utf-8");
    

    这应该让您的服务器相信您正在发送 JSON 数据。

    以后,我建议您熟悉 Wireshark 来解决此类问题。查看您发送的实际请求非常有帮助。如果做不到这一点,如果您不想这样做,您可以使用CURLOPT_DEBUGFUNCTION 获取 curl 发送的数据以进行验证。

    【讨论】:

    • 感谢您粘贴 ALL 的代码。如果人们不只粘贴代码中不相关部分的 1%,那么回答关于 SO 的问题会更容易......
    【解决方案2】:

    问题可能出在标题上。当您配置 curl_slist 标头时,我认为您应该将 curl_slist_append 的输出分配回标头:

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Accept: application/json");
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, "charset: utf-8");
    

    【讨论】:

    • 这是正确的解决方案。如果没有标头,则发送的 JSON 将包装在 {' ..... ',''} 字符串中。
    • "charsets: utf-8" 标头是什么?看起来是个错误。您可能应该改用Content-Type: application/json; charset=utf-8
    【解决方案3】:

    使用 json 解析器将数据发布到 node-red 时遇到同样的问题。
    我的解决方案是将字符串视为 HTML

    #include <curl/curl.h>
    
    int main (int argc, char *argv[]) {
        CURL *curl;
        CURLcode res;
    
        curl_global_init(CURL_GLOBAL_ALL);
        curl = curl_easy_init();
        if (curl == NULL) {
            return 128;
        }
        struct curl_slist *headers = NULL;
        curl_slist_append(headers, "Content-Type: application/json");
        curl_easy_setopt(curl, CURLOPT_URL, #yourURL);
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "age=42&sex=male");
    
        res = curl_easy_perform(curl);
    
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return res;
    }
    

    希望有人会觉得它有帮助。

    【讨论】:

      【解决方案4】:

      了解系统行为是否正确的一个关键部分是查看程序实际通过网络发送的内容。因此,检查字节流的另一种方法是在测试机器上的单独窗口中运行 netcat 实例,而不是将其指向您的服务器(和/或运行 Wireshark):

      nc -l 8080
      

      并将代码 (CURLOPT_URL) 指向“http://localhost:8080”。

      您需要在nc 窗口中按 Control-D 来终止连接,以便 curl 完成,但您也可以事先键入测试返回文本,这在以下情况下很有用你期待某种回复来测试。

      【讨论】:

        【解决方案5】:

        libcurl 将准确发送您要求它发送的字节。它根本不了解 JSON。

        请参阅@Lukasa 的出色且更详尽的答案以获得更好和更多的详细信息。

        【讨论】:

        • 非常感谢,@daniel-stenberg。那么你知道为什么我发送的字符串是"name" : "Pedro", "age" : "22" 而收到的字符串是{ '"name" : "Pedro", "age" : "22"' }吗?
        • 如果你没有发送'{'和'}',那么你就没有收到它们。然后我假设您接收数据的 JSON 处理程序自己将它们作为服务或类似的方式添加给您。
        • @PedroBaptistaAfonso 我认为这是因为标题,您指定的内容类型。
        • 我他妈的写了 libcurl。我知道它做什么和不做什么。 libcurl 中确实有 nothing 可以为 POST 数据添加大括号。没有。你可以声称所有你想要的。如果这样的大括号最终出现在接收端,则它们是由 libcurl 之外的其他东西添加的。
        • @blorkfish 丹尼尔是对的,而你是不正确的。有关完整说明,请参阅my answer
        【解决方案6】:

        我使用 json-c 对 json 进行编码和解码,效果很好。 文档也很容易理解。 https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/

        【讨论】:

          【解决方案7】:

          我遇到了类似的问题。

          我发现 curl 命令的 -libcurl 选项。 它帮助很大!只需将其添加到工作 curl 命令的末尾即可。

          最后它帮我创建了这段代码:

            CURLcode ret;
            CURL *hnd;
            struct curl_slist *slist1;
            std::string jsonstr = "{\"username\":\"bob\",\"password\":\"12345\"}";
          
            slist1 = NULL;
            slist1 = curl_slist_append(slist1, "Content-Type: application/json");
          
            hnd = curl_easy_init();
            curl_easy_setopt(hnd, CURLOPT_URL, "http://u/r/l");
            curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
            curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, jsonstr.c_str());
            curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.38.0");
            curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
            curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
            curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
            curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
          
            ret = curl_easy_perform(hnd);
          
            curl_easy_cleanup(hnd);
            hnd = NULL;
            curl_slist_free_all(slist1);
            slist1 = NULL;
          

          Express 接收这个 JSON 为:

          { username: 'bob', password: '12345' }
          

          我希望这会有所帮助!

          【讨论】:

          • 我刚刚发现了--libcurl 选项,因为这个答案。它有很大帮助!谢谢!
          猜你喜欢
          • 2014-06-05
          • 1970-01-01
          • 2021-09-03
          • 2011-05-13
          • 1970-01-01
          • 2014-02-26
          • 2014-05-27
          • 2015-02-28
          • 1970-01-01
          相关资源
          最近更新 更多