2011-11-24 72 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