12

我正在使用 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 对象进行编码?

非常感谢!

4

7 回答 7

21

问题可能出在标题上。当您配置 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");
于 2012-10-17T16:14:32.393 回答
15

首先,让我们注意几点。首先,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 发送的数据来验证它。

于 2017-01-18T08:24:16.170 回答
5

我遇到了类似的问题。

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

我希望这有帮助!

于 2016-05-02T08:28:24.417 回答
3

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

有关更好和更多详细信息,请参阅@Lukasa 的出色且更详尽的答案。

于 2012-08-15T17:40:48.133 回答
1

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

nc -l 8080

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

您需要Control-Dnc窗口中点击以终止连接,以便 curl 完成,但您也可以预先键入测试返回文本,如果您期望某种回复来测试,这可能很有用。

于 2017-07-07T12:28:10.307 回答
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;
}

希望有人会发现它有帮助。

于 2019-09-11T10:40:40.840 回答
-2

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

于 2016-10-26T08:57:20.190 回答