2011-11-24 66 views
10

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

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_POST,CURLOPT_HTTPPOST,CURLOPT_POSTFIELDS,CURLOPT_HTTPHEADER的组合。我已经阅读了许多关于这个主题的帖子(没有双关语),没有一个完全符合我的情况。有什么建议么?

[请注意,我通常没有任何URL编码的表单字段,如:HTTP://server/handler.php I =不&不=使用&这些=在&我=查询?]

回答

9

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

 

/*************************************************************************** 
*         _ _ ____ _ 
* Project      ___| | | | _ \| | 
*       /__| | | | |_) | | 
*       | (__| |_| | _ <| |___ 
*        \___|\___/|_| \_\_____| 
* 
* Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, 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; 
} 
 
+0

这是完美的。谢谢。 –

+1

不用担心。顺便说一句,如果你正在编写C++,你应该检查一下curlpp,它是一个直接的C libcurl的封装,并且是一个更好的方法来处理事情:http://curlpp.org/index.php/examples/71- example-21 –

12

您可以使用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不以任何方式修改有效负载,所以发送JSON数据非常方便。另请注意,当提供CURLOPT_POSTFIELDS时,它会自动启用CURLOPT_POST,因此不需要在请求中提供CURLOPT_POST

+0

你会以同样的方式发布JSON数组或字符串吗? [1,“blah”]不是一种形式,也没有键值对。你应该明确提到,如果是这样的话。 – dmitri

2

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

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

用分隔符或没有它。

3

需要Content-Type标题,以匹配application/json像op是问?

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

,我让设置的标头是正确添加什么是这个答案概括的唯一方法:JSON requests in C using libcurl