使用libcurl在C中进行JSON请求

时间:2012-08-15 17:21:27

标签: c json libcurl

我正在使用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, "charsets: 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, "charsets: 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对象的方法?

非常感谢!

7 个答案:

答案 0 :(得分:15)

问题可能出在标题上。在配置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, "charsets: utf-8");

答案 1 :(得分:12)

首先,让我们先注意几件事。首先,Daniel Stenberg是正确的(因为我希望他会,因为他编写了代码):libcurl不会将任何数据附加到您的代码中。我可以用这个示例程序来演示这个,这个示例程序就像您的示例,但有一些额外的setup / teardown代码。这是所有代码:此处没有其他内容:

#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, "charsets: 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, "charsets: 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, "charsets: utf-8");

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

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

答案 2 :(得分:3)

libcurl会发送完全您要求它发送的字节。它根本不了解JSON。

请参阅@Lukasa的优秀和更精细的答案,以获得更好的细节。

答案 3 :(得分:2)

我遇到了类似的问题。

我发现了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' }

我希望这有帮助!

答案 4 :(得分:1)

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

nc -l 8080

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

你需要点击nc窗口中的 Control-D 来终止连接以便curl完成,但你也可以预先输入测试返回文本,这可以是如果你期望某种回复来测试,那就很有用。

答案 5 :(得分:0)

使用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;
}

希望有人会有所帮助。

答案 6 :(得分:-2)

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