2011-09-27 11 views
13

Mój kod wygląda następująco:Wyślij ciąg na żądanie PUT z 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); 
} 

Który robi praca, program po prostu wisi na zawsze.

W test.php są nagłówki żądania uzyskać:

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" 
} 

Ale ciało jest pusta, oznacza brak danych JSON jest wysyłane z żądaniem.

Co chcę zrobić z libcurl jest w rzeczywistości niczym innym wtedy te skrypt z linii poleceń:

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

Odpowiedz

30

Got to :)

nie używaj

curl_easy_setopt(curl, CURLOPT_PUT, 1L); 

Złóż wniosek i niestandardowe wyślij dane jako POSTFIELDS:

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

Idealnie! A jeśli chcesz zapobiec/odrzucić odpowiedź z serwera, musisz ustawić "CURLOPT_WRITEFUNCTION", aby odebrać dane lub ustawić 'CURLOPT_WRITEDATA' na inny uchwyt' FILE * '. – karlphillip

+1

Dlaczego nie używać 'CURLOPT_UPLOAD' zamiast' CURLOPT_CUSTOMREQUEST', jak mówi [dokumentacja] (http://curl.haxx.se/libcurl/c/CURLOPT_PUT.html)? –

+0

Musiałem zrobić 'curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, NULL);' po 'curl_easy_perform (curl);' aby zapobiec, aby następne żądania były również żądaniami PUT. –

0

Ten nie zadziałał dla mnie. MUSIAŁem użyć UPLOAD i PUT, aby wykonać to poprawnie. Odpowiedź który pracował dla mnie jest tutaj:

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

Trzeba funkcję zwrotną dla readfile a następnie używać, aby skopiować dane z zwinięcie wskaźnika oferuje w tym zwrotnego.

W ostatecznym rozrachunku upewniłem się, że ustawiłem rozmiar pliku za pomocą CURLOPT_INFILESIZE lub CURLOPT_INFILESIZE_LARGE w zależności od ładunku. W przeciwnym razie pojawi się problem opublikowany w backstory.

Historia: Spodziewałem się żądanie JSON, ale przy użyciu opcji PUT Zwijanie i to podejście zwyczaj żądania uzyskać ten sam rezultat jak robi to za pośrednictwem konsoli

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 

Z drugiej strony dzięki czemu ten sam wniosek na konsoli i dodając pole danych (wstaw -d „” URL) dostaje mi, co chcę:

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"} 

W skrócie wygląda muszę wymyślić opcje CURL że zrobię równowartość PUT -d "". Widać również różnicę między obydwoma odpowiedziami, w jednym przypadku zwracany jest kod HTML, a połączenie jest zamknięte. W innym przypadku Treścią jest JSON i połączenie jest utrzymywane przy życiu.

podstawie tego, co znalazłam w przypadku błędu 411:

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

Problemem jest to, że długość treść musi być ustawiony niezależnie od tego, czy używasz CURLOPT_UPLOAD z CURLOPT_PUT lub opcji CUSTOM.

Jeśli masz strumień danych, wydaje ci się, że musisz użyć opcji READDATA i READFUNCTION, aby określić długość twoich danych.

Uwaga admin:

Pamiętaj, że w rep 50 wymagane jest komentować, więc nie mają wyboru, aby osobne posty w celu komunikowania się. Rozważ to, gdy myślisz o usunięciu tych postów, tak jak to miało miejsce w przeszłości.

1

CURLOPT_PUT jest przestarzałe i jest przez pewien czas. Powinieneś użyć CURLOPT_UPLOAD.

Dla nieznanych ilości danych za pomocą HTTP powinieneś używać kodowanego kodowania transferowego. W CURLOPT_UPLOAD docs powiedzieć:

Jeśli używasz HTTP PUT do 1,1 serwerze, można przesyłać dane bez znajomości rozmiaru przed rozpoczęciem transferu, jeśli używasz pofragmentowane kodowanie. Włączasz to, dodając nagłówek taki jak "Transfer-Encoding: chunked" z CURLOPT_HTTPHEADER. W przypadku HTTP 1.0 lub bez transferu z porcją należy określić rozmiar.

Powiązane problemy