【问题标题】:C++ libcurl not posting dataC++ libcurl 不发布数据
【发布时间】:2018-02-04 20:20:09
【问题描述】:

我正在开发一个 C++ 库,它使用 curl 库来执行对 Web 服务的 HTTP POST 请求。

我有一个函数负责执行 curl 和处理响应,这个函数调用另一个函数来设置 curl,因为它可以在多个地方使用相同的设置。

它已成功连接到 Web 服务,我可以看到返回的响应,但是没有任何发布数据发送到 Web 服务。

在我必须执行 HTTP 请求的代码下方。

第一个函数是curl执行的函数,它调用一个函数来初始化curl库,然后返回指向它的指针以供使用。

string response;
struct curl_slist *list = NULL;
const char * jsonString = ddEvent.getDDEventAsJSONString().c_str();
CURL *curl = this->initCurl(ddEvent, &response, list, &jsonString);
if (curl == NULL)
{
    return false;
}

list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
CURLcode res = curl_easy_perform(curl);

初始化curl的函数如下:

CURL * MyClass::initCurl(DDEvent ddEvent, string *response, struct curl_slist *list, const char **jsonString)
{
    CURL *curl = NULL;

    curl = curl_easy_init();
    if (curl == NULL)
    {
        cout << "Failed to initialise curl" << endl;
        return NULL;
    }
    stringstream url_stream;
    url_stream << "http://192.168.1.123";
    string url= dd_url_stream.str();

    cout << "Using URL: " << url<< endl;

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &MyClass::curlResponseWriteCallback);
    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, *jsonString);

    return curl;
}

另外,发布数据是一个 JSON 字符串,它不是一个键/值发布的表单数据。

下面是 curl 详细模式的输出

Using JSON string {"title":"HTTP Event Teesg","text":"Test warning event","alert_type":"success","tags":["simple_string_tag"]}
Using URL: http://192.168.1.123
* About to connect() to 192.168.1.123 port 80 (#0)
*   Trying 192.168.1.123...
* Connected to 192.168.1.123 (192.168.1.123) port 80 (#0)
> POST / HTTP/1.1
Host: 192.168.1.123
Accept: */*
Content-Type: application/json
Content-Length: 0

< HTTP/1.1 200 OK
< Date: Sun, 04 Feb 2018 20:11:12 GMT
< Server: Apache/2.4.6 (CentOS) PHP/5.6.32
< X-Powered-By: PHP/5.6.32
< X-XSS-Protection: 1; mode=block
< Content-Length: 52
< Content-Type: text/html; charset=UTF-8
<

【问题讨论】:

  • 您是否有理由不直接为 url 分配值 "http://192.168.1.123",而是使用 stringstream?
  • 我还看到您的 init 函数采用指向 std::basic_string 的指针并将该指针传递给 curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);。你能验证这个函数期待的是std::basic_string *而不是char *
  • 最后评论,您可能需要“转义”帖子数据。不确定这是否已经完成,但阅读CURLOPT_POSTFIELDS,数据应该是url encoded
  • @smac89 实际 URL 指向第 3 方 Web 服务,因此会有其他参数,因为这个问题我将它指向了测试服务器上的本地网页,所以它通常不像那样
  • @smac89 关于您对响应指针的评论,响应字符串被正确填充,因为我可以看到响应被打印回来

标签: c++ curl


【解决方案1】:

传出请求中的Content-Length: 0 表明您传递给CURLOPT_POSTFIELDS 的数据长度为零。

请注意,CURLOPT_POSTFIELDS 不会复制数据,它只是指向您的内存,因此您可能需要确保数据在 libcurl 需要它的整个时间内仍然存在。由于您没有向我们展示整个程序,我们无法真正告诉您这是如何发生的。

最后:为什么不直接将 'char *' 传递给 initCurl 而不是需要在方法中取消引用的 'char **'?我觉得这很奇怪。

【讨论】:

    【解决方案2】:

    似乎 ddEvent.getDDEventAsJSONString() 返回了一个临时的 std::string 对象。 将其保存在局部变量中,然后将其作为引用传递。

    std::string jsonString = ddEvent.getDDEventAsJSONString();
    this->initCurl(ddEvent, &response, list, jsonString);
    
    CURL * MyClass::initCurl(DDEvent ddEvent, string *response, struct curl_slist *list, const std::string& jsonString)
    

    在调用 curl_easy_perform() 之前,您必须保持字符串处于活动状态,因为 CURLOPT_POSTFIELDS 不会将字符串复制到 libcurl 中。

    作为 'char *' 参数传递给 libcurl 的字符串由库复制;因此,与指针参数关联的字符串存储可能会在 curl_easy_setopt 返回后被覆盖。此规则的唯一例外实际上是 CURLOPT_POSTFIELDS,但复制字符串 CURLOPT_COPYPOSTFIELDS 的替代方案有一些您需要阅读的使用特征。

    在 jsonString 的生命范围内调用 curl_easy_perform 的代码中没有问题。但是,如果您打算稍后调用该函数,请使用 CURLOPT_COPYPOSTFIELDS 代替 CURLOPT_POSTFIELDS,它会复制并记住要发布的数据。

    【讨论】:

      猜你喜欢
      • 2012-07-20
      • 2015-01-21
      • 2021-01-04
      • 2019-01-05
      • 1970-01-01
      • 2013-02-26
      • 2014-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多