2011-11-24 12 views
10

Attualmente il mio programma C++ invoca il ricciolo attraverso una pipe (popen("curl ...")) per POST un file di dati JSON su un server web. Questo ha evidenti limiti di prestazioni dovuti alla necessità di salvare il JSON in un file e di richiamare l'arricciatura in una subshell. Mi piacerebbe riscriverlo per usare libcurl, ma non mi è chiaro come farlo. La linea di comando passaggio popen() è:Come si esegue il POST di un buffer di JSON utilizzando libcurl?

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

I dati JSON (circa 3K) è seduto in un buffer in RAM prima devo postarla. Mi aspettavo di usare CURLOPT_READFUNCTION di libcurl per lo spooling del buffer su libcurl (ma sono aperto alle alternative) e CURLOPT_WRITEFUNCTION per catturare la risposta del server, in modo simile a come ho letto la risposta dalla pipe di popen.

Tutto ciò sembra semplice. Qual è la confusione tra la combinazione di CURLOPT_POST, CURLOPT_HTTPPOST, CURLOPT_POSTFIELDS, CURLOPT_HTTPHEADER di cui ho bisogno. Ho letto molti post su questo argomento (nessun gioco di parole) e nessuno corrisponde esattamente al mio scenario. Eventuali suggerimenti?

[Si noti che io normalmente non ho alcun campi del modulo con codifica URL, come questo: http: //server/handler.php I = non & non = Usa & questi = in & mia interrogazione =?]

risposta

9

C'è esempio di codice per questo qui: 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

Questo è perfetto. Grazie. –

+1

Nessun problema. A proposito, se stai scrivendo C++ dovresti dare un'occhiata a curlpp, che è un wrapper per la dritta C libcurl, ed è un modo molto più carino di andare sulle cose: http://curlpp.org/index.php/examples/71- esempio-21 –

12

È possibile utilizzare 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); 

Poiché CURLOPT_POSTFIELDS non modifica il carico utile in alcun modo, è molto conveniente per il POSTing dei dati JSON. Si noti inoltre che, quando viene fornito CURLOPT_POSTFIELDS, abilita automaticamente CURLOPT_POST quindi non è necessario fornire CURLOPT_POST nella richiesta.

+0

Vuoi pubblicare un array JSON o una stringa nello stesso modo? [1, "blah"] non è una forma e non ci sono coppie chiave-valore. Probabilmente dovresti dirlo esplicitamente se questo è il caso. – dmitri

2

Inoltre, è possibile utilizzare l'ingresso RAW invece di aggiungere backslash aggiuntivi:

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

con delimitatore o senza di essa.

3

E l'intestazione Content-Type richiesta corrisponde a application/json proprio come l'op sta chiedendo?

Utilizzando lo CURLOPT_POSTFIELDS da due risposte sopra e CURLOPT_POST, lo Content-Type viene automaticamente impostato su application/x-www-form-urlencoded.

L'unico modo per me per ottenere le intestazioni impostate correttamente è stato quello di aggiungere ciò che viene descritto in questa risposta: JSON requests in C using libcurl

Problemi correlati