使用 libcurl 在 PUT 请求中发送字符串

发布于 2024-12-07 04:55:02 字数 1124 浏览 0 评论 0原文

我的代码如下所示:

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

My code looks like this:

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

Which doesnt work, the program just hangs forever.

In test.php these are the request headers I get:

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

But the body is empty, means, no json data is sent with the request.

What I want to do with libcurl is actually nothing else then these command line script:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

杯别 2024-12-14 04:55:02

明白了:)

不要使用

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

Got it :)

Dont use

curl_easy_setopt(curl, CURLOPT_PUT, 1L);

Make a custom request and send the data as 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);
}
唠甜嗑 2024-12-14 04:55:02

CURLOPT_PUT 已被弃用,并且已经有一段时间了。您应该使用CURLOPT_UPLOAD

对于 HTTP 未知数量的数据,您应该使用分块传输编码。 CURLOPT_UPLOAD 文档说:

如果您使用 PUT 到 HTTP 1.1 服务器,并且使用分块编码,则可以在开始传输之前在不知道大小的情况下上传数据。您可以通过使用 CURLOPT_HTTPHEADER 添加“Transfer-Encoding: chunked”之类的标头来启用此功能。使用 HTTP 1.0 或不使用分块传输,您必须指定大小。

CURLOPT_PUT is deprecated, and has been for a while. You should use CURLOPT_UPLOAD.

For unknown amounts of data with HTTP, you should be using chunked transfer encoding. The CURLOPT_UPLOAD docs say:

If you use PUT to a HTTP 1.1 server, you can upload data without knowing the size before starting the transfer 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.

千柳 2024-12-14 04:55:02

这对我不起作用。
我必须使用 UPLOAD 和 PUT 才能正确执行此操作。
对我有用的答案在这里:

如何在不使用文件指针的情况下在 libcurl 中发送长 PUT 数据?

您需要 READFILE 的回调函数,然后使用它来复制您的回调中提供的指针curl 的数据。

最终对我有用的是确保根据您的负载使用 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_PUT 的 CURLOPT_UPLOAD 还是 CUSTOM 选项,都需要设置内容长度。

因此,如果您有数据流,则似乎必须使用 READDATA 和 READFUNCTION 选项来确定数据的长度。

管理员注意:

请记住,需要代表 50 才能发表评论,因此我别无选择,只能单独发表帖子以便进行交流。因此,当您考虑像过去那样删除这些帖子时,请考虑这一点。

This one did not work for me.
I HAD to use UPLOAD and PUT to perform this correctly.
The answer that worked for me is here:

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

You need the callback function for READFILE and then use that to copy your data to the pointer curl offers in that callback.

What ultimately worked for me was to make sure I set the FILE size using either CURLOPT_INFILESIZE or CURLOPT_INFILESIZE_LARGE depending on your payload. Otherwise you get the problem posted in the backstory.

Backstory:
I was expecting a JSON request but using either the PUT CURL option or this custom request approach I get the same result as doing this via 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

On the other hand making the same request on the console and adding a data field (PUT -d "" URL)gets me what I want:

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 summary it looks like I need to figure out the CURL options that'll do the equivalent of PUT -d "". Also you can see the difference between both response, in one case the return is HTML and the connection is closed. In the other case the Content is JSON and the connection is kept alive.

Based on what I've found on error 411:

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

The problem is that the content length needs to be set regardless of whether you use CURLOPT_UPLOAD with CURLOPT_PUT or the CUSTOM option.

So, if you have a stream of data you have it seems you HAVE to use the READDATA and READFUNCTION options to determine the length of your data.

Note to admin:

Keep in mind rep 50 is REQUIRED to post comments so I HAVE NO CHOICE but to make separate posts in order to communicate. So consider this when you are thinking about deleting these posts as it has been done in the past.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文