使用libcurl在C中进行JSON请求

我在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对象的方法?

非常感谢!

问题可能在于标题。 在配置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"); 

首先,让我们注意一些事情。 首先,Daniel Stenberg是正确的(因为我希望他会,因为他编写了代码):libcurl不会将任何数据附加到您的代码中。 我可以用这个示例程序演示这个,这个示例程序就像您的示例,但有一些额外的设置/拆卸代码。 这是所有的代码:这里没有别的东西:

 #include  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来获取正在发送的数据以validation它。

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

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

我遇到了类似的问题。

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

我希望这有帮助!

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

 nc -l 8080 

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

您需要在nc窗口中按Control-D来终止连接以便curl完成,但您也可以事先键入测试返回文本,如果您期望某种类型的回复进行测试,这可能很有用。

我用json-c编码和解码jsons,它运行得很好。 文档也很容易理解。 https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/