【问题标题】:How do I POST a buffer of JSON using libcurl?如何使用 libcurl 发布 JSON 缓冲区?
【发布时间】:2012-01-05 06:49:25
【问题描述】:

我的 C++ 程序当前通过管道 (popen("curl ...")) 调用 curl 以将 JSON 数据文件 POST 到 Web 服务器。由于需要将 JSON 保存到文件并在子 shell 中调用 curl,这具有明显的性能限制。我想重写它以使用 libcurl,但我不清楚如何做到这一点。我传递给popen() 的命令行是:

curl -s -S -D /dev/null -H "Content-Type: application/json" -X POST -d file-of-json http://server/handler.php

JSON 数据(大约 3K)在我需要发布之前位于 RAM 中的缓冲区中。我期待使用 libcurl 的 CURLOPT_READFUNCTION 将缓冲区假脱机到 libcurl(但我对替代方案持开放态度),并使用 CURLOPT_WRITEFUNCTION 来捕获服务器的回复,类似于我从 popen 的管道中读取回复的方式。

这一切看起来都很简单。令人困惑的是我需要CURLOPT_POSTCURLOPT_HTTPPOSTCURLOPT_POSTFIELDSCURLOPT_HTTPHEADER 的哪个组合。我已经阅读了很多关于这个主题的帖子(没有双关语),没有一个完全符合我的情况。有什么建议吗?

[请注意,我通常没有任何 URL 编码的表单字段,例如:http://server/handler.php?I=do&not=use&these=in&my=query]

【问题讨论】:

    标签: json http post http-post libcurl


    【解决方案1】:

    正如操作员要求的那样,与 application/json 匹配所需的 Content-Type 标头怎么样?

    使用上述两个答案中的CURLOPT_POSTFIELDS 以及CURLOPT_POSTContent-Type 会自动设置为application/x-www-form-urlencoded

    正确设置标题的唯一方法是添加此答案中概述的内容:JSON requests in C using libcurl

    【讨论】:

      【解决方案2】:

      另外,您可以使用 RAW 输入而不是添加额外的反斜杠:

      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, R"anydelim( {"hi" : "there"} )anydelim");
      

      有或没有分隔符。

      【讨论】:

        【解决方案3】:

        你可以使用CURLOPT_POSTFIELDS:

        CURL *curl = curl_easy_init();
        
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/api/endpoint");
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"hi\" : \"there\"}");
        
        curl_easy_perform(curl);
        

        由于CURLOPT_POSTFIELDS不会以任何方式修改payload,所以很方便POST JSON数据。另请注意,当提供CURLOPT_POSTFIELDS 时,它会自动启用CURLOPT_POST,因此无需在请求中提供CURLOPT_POST

        【讨论】:

        • 您会以相同的方式发布 JSON 数组或字符串吗? [1, "blah"] 不是一种形式,也没有键值对。如果是这种情况,您可能应该明确提及。
        【解决方案4】:

        这里有示例代码:http://curl.haxx.se/libcurl/c/post-callback.html

        /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* An example source code that issues a HTTP POST and we provide the actual * data through a read callback. */ #include #include #include const char data[]="this is what we post to the silly web server"; struct WriteThis { const char *readptr; int sizeleft; }; static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) { struct WriteThis *pooh = (struct WriteThis *)userp; if(size*nmemb sizeleft) { *(char *)ptr = pooh->readptr[0]; /* copy one single byte */ pooh->readptr++; /* advance pointer */ pooh->sizeleft--; /* less data left */ return 1; /* we return 1 byte at a time! */ } return 0; /* no more data left to deliver */ } int main(void) { CURL *curl; CURLcode res; struct WriteThis pooh; pooh.readptr = data; pooh.sizeleft = strlen(data); curl = curl_easy_init(); if(curl) { /* First set the URL that is about to receive our POST. */ curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/index.cgi"); /* Now specify we want to POST data */ curl_easy_setopt(curl, CURLOPT_POST, 1L); /* we want to use our own read function */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); /* pointer to pass to our read function */ curl_easy_setopt(curl, CURLOPT_READDATA, &pooh); /* get verbose debug output please */ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); /* If you use POST to a HTTP 1.1 server, you can send data without knowing the size before starting the POST if you use chunked encoding. You enable this by adding a header like "Transfer-Encoding: chunked" with CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must specify the size in the request. */ #ifdef USE_CHUNKED { struct curl_slist *chunk = NULL; chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked"); res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); /* use curl_slist_free_all() after the *perform() call to free this list again */ } #else /* Set the expected POST size. If you want to POST large amounts of data, consider CURLOPT_POSTFIELDSIZE_LARGE */ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)pooh.sizeleft); #endif #ifdef DISABLE_EXPECT /* Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. You can disable this header with CURLOPT_HTTPHEADER as usual. NOTE: if you want chunked transfer too, you need to combine these two since you can only set one list of headers with CURLOPT_HTTPHEADER. */ /* A less good option would be to enforce HTTP 1.0, but that might also have other implications. */ { struct curl_slist *chunk = NULL; chunk = curl_slist_append(chunk, "Expect:"); res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); /* use curl_slist_free_all() after the *perform() call to free this list again */ } #endif /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* always cleanup */ curl_easy_cleanup(curl); } return 0; }

        【讨论】:

        • 不用担心。顺便说一句,如果您正在编写 C++,您应该查看 curlpp,它是直接 C libcurl 的包装器,并且是一种更好的处理方式:curlpp.org/index.php/examples/71-example-21
        • 在哪里提及服务器的 API 密钥?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-11
        • 2011-04-02
        • 1970-01-01
        • 2022-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多