Отправить строку в запросе PUT с помощью libcurl - PullRequest
14 голосов
/ 27 сентября 2011

Мой код выглядит так:

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);
}

Что не работает, программа просто зависает навсегда.

В test.php я получаю заголовки запроса:

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

Но тело пустое, значит, данные json с запросом не отправляются.

То, что я хочу сделать с libcurl, на самом деле не что иное, как сценарий командной строки:

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

Ответы [ 3 ]

40 голосов
/ 27 сентября 2011

Понял :)

Не использовать

curl_easy_setopt(curl, CURLOPT_PUT, 1L);

Сделайте заказ и отправьте данные в виде 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);
}
1 голос
/ 21 января 2015

CURLOPT_PUT устарело, и было некоторое время.Вы должны использовать CURLOPT_UPLOAD.

Для неизвестных объемов данных с HTTP вы должны использовать кодирование передачи по частям.Документы CURLOPT_UPLOAD говорят:

Если вы используете PUT на сервер HTTP 1.1, вы можете загружать данные, не зная размера, до начала передачи, если вы используете чанкованное кодирование.Вы включаете это, добавляя заголовок, такой как «Transfer-Encoding: chunked» с помощью CURLOPT_HTTPHEADER.С HTTP 1.0 или без чанкованной передачи вы должны указать размер.

0 голосов
/ 18 января 2015

Этот не работал для меня.Я должен был использовать UPLOAD и PUT, чтобы выполнить это правильно.Ответ, который работал для меня, здесь:

Как отправить длинные данные PUT в libcurl без использования файловых указателей?

Вам нужна функция обратного вызова для READFILE, а затемиспользуйте это, чтобы скопировать ваши данные в предложения указателя скручивания в этом обратном вызове.

В конечном итоге мне удалось убедиться, что я установил размер ФАЙЛА, используя CURLOPT_INFILESIZE или CURLOPT_INFILESIZE_LARGE в зависимости от вашей полезной нагрузки.В противном случае вы получите сообщение о проблеме в предыстории.

Предыстория: я ожидал запрос JSON, но, используя либо опцию PUT CURL, либо этот пользовательский подход, я получаю тот же результат, что и через консоль

 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

С другой стороны, выполнение одного и того же запроса на консоли и добавление поля данных (PUT -d "" URL) дает мне то, что я хочу:

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

В целом, похоже, что янужно выяснить параметры CURL, которые будут эквивалентны PUT -d "".Также вы можете увидеть разницу между обоими ответами, в одном случае возвращаемое значение - HTML, а соединение закрыто.В другом случае Контент представляет собой JSON, и соединение сохраняется.

На основании того, что я обнаружил при ошибке 411:

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

Проблема заключается в том, чточто длина контента должна быть установлена ​​независимо от того, используете ли вы CURLOPT_UPLOAD с CURLOPT_PUT или опцию CUSTOM.

Итак, если у вас есть поток данных, у вас есть необходимость использовать опции READDATA и READFUNCTION дляопределите длину ваших данных.

Примечание для администратора:

Имейте в виду, что rep 50 ОБЯЗАТЕЛЬНО оставлять комментарии, поэтому у меня нет выбора, кроме как создавать отдельные сообщения, чтобы общаться.Поэтому подумайте об этом, когда вы думаете об удалении этих постов, как это было сделано в прошлом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...