2011-09-27 13 views
13

Il mio codice è simile al seguente:Invia stringa nella richiesta PUT con libcurl

curl = curl_easy_init(); 

if (curl) { 
    headers = curl_slist_append(headers, client_id_header); 
    headers = curl_slist_append(headers, "Content-Type: application/json"); 

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_URL, "127.0.0.1/test.php"); 
    curl_easy_setopt(curl, CURLOPT_PUT, 1L); 

    res = curl_easy_perform(curl); 
    res = curl_easy_send(curl, json_struct, strlen(json_struct), &io_len); 

    curl_slist_free_all(headers); 
    curl_easy_cleanup(curl); 
} 

Che pretende molto lavoro, il programma si blocca solo per sempre.

In test.php queste sono le intestazioni di richiesta ottengo:

array(6) { 
    ["Host"]=> 
    string(9) "127.0.0.1" 
    ["Accept"]=> 
    string(3) "*/*" 
    ["Transfer-Encoding"]=> 
    string(7) "chunked" 
    ["X-ClientId"]=> 
    string(36) "php_..." 
    ["Content-Type"]=> 
    string(16) "application/json" 
    ["Expect"]=> 
    string(12) "100-continue" 
} 

Ma il corpo è vuoto, significa, non ci sono dati JSON viene inviato con la richiesta.

Quello che voglio fare con libcurl è in realtà niente altro allora questi script della riga di comando:

curl -X PUT -H "Content-Type: application/json" -d '... some json ...' 127.0.0.1/test.php 

risposta

30

Got it :)

Non utilizzare

curl_easy_setopt(curl, CURLOPT_PUT, 1L); 

fare una richiesta personalizzata e inviare i dati come POST FIELD:

curl = curl_easy_init(); 

if (curl) { 
    headers = curl_slist_append(headers, client_id_header); 
    headers = curl_slist_append(headers, "Content-Type: application/json"); 

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_URL, request_url); 
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); /* !!! */ 

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_struct); /* data goes here */ 

    res = curl_easy_perform(curl); 

    curl_slist_free_all(headers); 
    curl_easy_cleanup(curl); 
} 
+0

Perfetto! E se si desidera impedire/sopprimere la risposta dal server, è necessario impostare 'CURLOPT_WRITEFUNCTION' per ricevere i dati o impostare' CURLOPT_WRITEDATA' su un diverso handle 'FILE * '. – karlphillip

+1

Perché non usare 'CURLOPT_UPLOAD' invece di' CURLOPT_CUSTOMREQUEST', come la [documentazione] (http://curl.haxx.se/libcurl/c/CURLOPT_PUT.html) dice? –

+0

Ho dovuto eseguire 'curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, NULL);' dopo "curl_easy_perform (curl);" per evitare che anche le richieste successive vengano richieste PUT. –

0

Questo non ha funzionato per me. Ho dovuto usare UPLOAD e PUT per farlo correttamente. La risposta che ha funzionato per me è qui:

How do I send long PUT data in libcurl without using file pointers?

avete bisogno della funzione di callback per ReadFile e quindi utilizzare tale per copiare i dati al puntatore ricciolo offre in quel callback.

Ciò che alla fine ha funzionato per me è stato assicurarmi di impostare la dimensione FILE utilizzando CURLOPT_INFILESIZE o CURLOPT_INFILESIZE_LARGE a seconda del payload. Altrimenti si ottiene il problema pubblicato nel backstory.

Backstory: mi aspettavo una richiesta di JSON, ma utilizzando l'opzione PUT CURL o questo approccio richiesta personalizzato ottengo lo stesso risultato di questa operazione tramite console

curl -H "Accept:application/json" -H "Authorization:authxxxx" -v -X PUT "http://server.xxxdomain.com/path0/path1/path2/state?data1=1&data2=1421468910543&data3=-3" 


* Adding handle: conn: 0x7fd752003a00 
* Adding handle: send: 0 
* Adding handle: recv: 0 
* Curl_addHandleToPipeline: length: 1 
* - Conn 0 (0x7fd752003a00) send_pipe: 1, recv_pipe: 0 
* About to connect() to server.xxxdomain.com port 80 (#0) 
* Trying ipaddress... 
* Connected to api-qos.boingodev.com (ipaddress) port 80 (#0) 
> PUT /path0/path1/path2/done?data1=1&data2=1421468910543&data3=-3 HTTP/1.1 
> User-Agent: curl/7.30.0 
> Host: server.xxxdomain.com 
> Accept:application/json 
> Authorization:authxxxx 
> 
< HTTP/1.1 411 Length Required 
* Server nginx/1.1.19 is not blacklisted 
< Server: nginx/1.1.19 
< Date: Sat, 17 Jan 2015 04:32:18 GMT 
< Content-Type: text/html 
< Content-Length: 181 
< Connection: close 
< 
<html> 
<head><title>411 Length Required</title></head> 
<body bgcolor="white"> 
<center><h1>411 Length Required</h1></center> 
<hr><center>nginx/1.1.19</center> 
</body> 
</html> 
* Closing connection 0 

D'altra parte fare la stessa richiesta sulla console e l'aggiunta di un campo di dati (PUT -d "" URL) mi fa quello che voglio:

curl -H "Accept:application/json" -H "authxxxx" -v -X PUT -d "" "http://server.xxxdomain.com/path0/path1/path2/state?data1=1&data2=1421468910543&data3=-3" 
* Adding handle: conn: 0x7fe8aa803a00 
* Adding handle: send: 0 
* Adding handle: recv: 0 
* Curl_addHandleToPipeline: length: 1 
* - Conn 0 (0x7fe8aa803a00) send_pipe: 1, recv_pipe: 0 
* About to connect() to server.xxxdomain.com port 80 (#0) 
* Trying ipaddress... 
* Connected to server.xxxdomain.com (ipaddress) port 80 (#0) 
> PUT /path0/path1/path2/state?data1=1&data2=1421468910543&data3=-3" HTTP/1.1 
> User-Agent: curl/7.30.0 
> Host: server.xxxdomain.com 
> Accept:application/json 
> Authorization:authxxxx 
> Content-Length: 0 
> Content-Type: application/x-www-form-urlencoded 
> 
< HTTP/1.1 200 OK 
* Server nginx/1.1.19 is not blacklisted 
< Server: nginx/1.1.19 
< Date: Sat, 17 Jan 2015 17:16:59 GMT 
< Content-Type: application/json 
< Content-Length: 32 
< Connection: keep-alive 
< 
* Connection #0 to host server.xxxdomain.com left intact 
{"code":"0","message":"Success"} 

In sintesi sembra che ho bisogno di capire le opzioni CURL che farà l'equivalente di PUT -d "". Inoltre puoi vedere la differenza tra entrambe le risposte, in un caso il ritorno è HTML e la connessione è chiusa. Nell'altro caso il Contenuto è JSON e la connessione viene mantenuta attiva.

sulla base di quello che ho trovato in caso di errore 411:

http://www.checkupdown.com/status/E411.html

Il problema è che la lunghezza del contenuto deve essere impostato indipendentemente dal fatto che si utilizza CURLOPT_UPLOAD con CURLOPT_PUT o l'opzione Personalizzata.

Quindi, se si dispone di un flusso di dati, sembra che si debbano utilizzare le opzioni READDATA e READFUNCTION per determinare la lunghezza dei dati.

Nota di admin:

Tenete a mente rep 50 è necessario per inviare commenti in modo non ho altra scelta ma per rendere i messaggi separati al fine di comunicare. Considera questo quando stai pensando di cancellare questi post come è stato fatto in passato.

1

CURLOPT_PUT è deprecato ed è stato per un po '. Dovresti usare CURLOPT_UPLOAD.

Per quantità sconosciute di dati con HTTP, si dovrebbe utilizzare la codifica di trasferimento Chunked. I CURLOPT_UPLOAD documenti dicono:

Se si utilizza PUT a un server HTTP 1.1, è possibile caricare i dati senza conoscere la taglia prima di iniziare il trasferimento, se si utilizza la codifica Chunked. Puoi abilitarlo aggiungendo un'intestazione come "Transfer-Encoding: chunked" con CURLOPT_HTTPHEADER. Con HTTP 1.0 o senza trasferimento Chunked, è necessario specificare la dimensione.