2011-11-24 9 views
10

Mój program w C++ aktualnie wywołuje zwijanie się przez potok (popen("curl ...")) do POST pliku danych JSON do serwera WWW. Ma to oczywiste ograniczenia wydajności ze względu na konieczność zapisania pliku JSON w pliku i wywołania zwinięcia w podpowłoce. Chciałbym przerobić go na libcurl, ale nie jest dla mnie jasne, jak to zrobić. Linia komend mijam do popen() jest:Jak POST buforować JSON przy użyciu libcurl?

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

dane JSON (około 3K) siedzi w buforze pamięci RAM przed muszę go zakładać. Spodziewałem się użyć CURLOPT_READFUNCTION libcurla do buforowania bufora do libcurl (ale jestem otwarty na alternatywy), a CURLOPT_WRITEFUNCTION do przechwytywania odpowiedzi serwera, podobnie jak czytałem odpowiedź z rury popena.

Wszystko to wydaje się proste. To, co jest mylące, to która kombinacja CURLOPT_POST, CURLOPT_HTTPPOST, CURLOPT_POSTFIELDS, CURLOPT_HTTPHEADER jest mi potrzebna. Przeczytałem wiele postów na ten temat (gra słów nie przeznaczonych) i żadne dokładnie nie pasuje do mojego scenariusza. Jakieś sugestie?

[Zauważ, że zazwyczaj nie mają żadnych pól formularza URL kodowane w następujący sposób: http: //server/handler.php I = nie = nie & używać & te = w = & moja kwerenda?]

Odpowiedz

9

jest przykładem na to kod tutaj: 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

To jest doskonały. Dzięki. –

+1

Bez obaw. BTW, jeśli piszesz C++ powinieneś sprawdzić curlpp, który jest wrapperem dla prostej C libcurl i jest o wiele ładniejszym sposobem na robienie rzeczy: http://curlpp.org/index.php/examples/71- example-21 –

12

można użyć 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); 

Ponieważ CURLOPT_POSTFIELDS nie modyfikuje ładunku w żaden sposób, jest to bardzo wygodne dla danych POSTing JSON. Należy również pamiętać, że po dostarczeniu CURLOPT_POSTFIELDS automatycznie włącza się CURLOPT_POST, więc nie ma potrzeby podawania CURLOPT_POST w żądaniu.

+0

Czy umieścisz tablicę JSON lub ciąg znaków w ten sam sposób? [1, "bla"] nie jest formą i nie ma par klucz-wartość. Powinieneś chyba wyraźnie o tym wspomnieć. – dmitri

2

Ponadto, można użyć wejście RAW zamiast dodawania dodatkowych backslashy:

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

z separatora lub bez niego.

3

Co z wymaganym nagłówkiemdopasowanym do application/json, tak jak pyta operatora?

Przy użyciu CURLOPT_POSTFIELDS z dwóch powyższych odpowiedzi, a także CURLOPT_POST, Content-Type zostaje automatycznie ustawiony na application/x-www-form-urlencoded.

Jedynym sposobem dla mnie, aby uzyskać nagłówki prawidłowo ustawione było dodać to, co jest opisane w tej odpowiedzi: JSON requests in C using libcurl