简体   繁体   English

在 C/C++ 中制作 libcurl json 发布请求

[英]Making libcurl json post request in C/C++

I am writing a Qt application, and I have a button which is supposed to register a user.我正在编写一个 Qt 应用程序,并且我有一个应该注册用户的按钮。 I'm using the following libraries:我正在使用以下库:

  1. https://github.com/nlohmann/json <- for json serialization/deserialization https://github.com/nlohmann/json <- 用于 json 序列化/反序列化
  2. libcurl库库尔

My goal is to be able to make a post request to the following endpoint: http://localhost:8000/api/register我的目标是能够向以下端点发出发布请求:http://localhost:8000/api/register

It is expecting a POST of Content-Type: application/json, of utf-8, with a json body like this:它期待 utf-8 的 Content-Type: application/json 的 POST,具有如下 json 主体:

{
    "username": "test", 
    "password": "test"
}

The post request goes through, but the response is giving errors.发布请求通过,但响应给出错误。 I'm trying to pinpoint if this is an issue with my libcurl code, or if it's an error with my python django application.我试图确定这是我的 libcurl 代码的问题,还是我的 python django 应用程序的错误。

Here is the verbose output of the libcurl code:这是 libcurl 代码的详细 output :

E0125 08:52:00.886679  5816 API.h:43] {"password":"test2","username":"test"}
* STATE: INIT => CONNECT handle 0x2489d6b0bf8; line 1835 (connection #-5000)
* Added connection 0. The cache now contains 1 members
* family0 == v4, family1 == v6
*   Trying 127.0.0.1:8000...
* STATE: CONNECT => CONNECTING handle 0x2489d6b0bf8; line 1896 (connection #0)
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
* STATE: CONNECTING => PROTOCONNECT handle 0x2489d6b0bf8; line 2030 (connection #0)
* STATE: PROTOCONNECT => DO handle 0x2489d6b0bf8; line 2051 (connection #0)
> POST /api/register HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Jellybean-Launcher
Content-Type: application/json; charset: utf-8
Accept: application/json
Content-Length: 8

* STATE: DO => DID handle 0x2489d6b0bf8; line 2147 (connection #0)
* STATE: DID => PERFORMING handle 0x2489d6b0bf8; line 2266 (connection #0)
* Mark bundle as not supporting multiuse
* HTTP 1.1 or later with persistent connection
< HTTP/1.1 400 Bad Request
< Date: Tue, 25 Jan 2022 16:52:00 GMT
< Server: WSGIServer/0.2 CPython/3.9.7
< Content-Type: application/json
< Vary: Accept, Cookie
< Allow: POST, OPTIONS
< X-Frame-Options: DENY
< Content-Length: 109
< X-Content-Type-Options: nosniff
< Referrer-Policy: same-origin
<
{"detail":"JSON parse error - 'utf-8' codec can't decode byte 0xdd in position 0: invalid continuation byte"}* STATE: PERFORMING => DONE handle 0x2489d6b0bf8; line 2465 (connection #0)
* multi_done: status: 0 prem: 0 done: 0
* Connection #0 to host 127.0.0.1 left intact
* Expire cleared (transfer 0x2489d6b0bf8)

Here is the libcurl code itself:这是 libcurl 代码本身:

void RegisterUser(std::string username, std::string password)
{
    curl_global_init(CURL_GLOBAL_ALL);

    nlohmann::json json_data;
    json_data["username"] = "test";
    json_data["password"] = "test2";
    CURL* curl = curl_easy_init();
    CURLcode res;

    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, GetRegistrationURL().c_str());
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        
        struct curl_slist* chunk = NULL;
        chunk = curl_slist_append(chunk, "Content-Type: application/json; charset: utf-8");
        chunk = curl_slist_append(chunk, "Accept: application/json");

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
        curl_easy_setopt(curl, CURLOPT_POST, 1L);

        /* Set the expected POST size. */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str()));
        LOG(ERROR) << json_data.dump().c_str();
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str());
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Jellybean-Launcher");


        res = curl_easy_perform(curl);
        if (res == CURLE_OK)
        {
            //res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);
        }
        curl_easy_cleanup(curl);
        curl_slist_free_all(chunk);
    }

    curl_global_cleanup();

}

GetRegistrationURL() Returns an std::string which is scoped based on if you're in a development build or not. GetRegistrationURL()返回一个 std::string,其范围取决于您是否处于开发构建中。 During development builds, it always passes localhost, and in release builds it passes the live web url.在开发构建期间,它总是通过 localhost,而在发布构建中,它通过实时 web url。

Does anyone have any idea of what I may be doing wrong here?有谁知道我在这里可能做错了什么?

The first error is in the line curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str()));第一个错误是curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str())); . . sizeof does not do what you suppose it does. sizeof并没有按照您的设想进行。

Yet another error is in the line curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str());另一个错误是curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str()); stores a pointer to an inside of a temporary data json_data.dump() , it causes undefined behavior, possibly sending a garbage.存储指向临时数据内部的指针json_data.dump() ,它会导致未定义的行为,可能会发送垃圾。 The error 'utf-8' codec can't decode byte 0xdd hints about the Microsoft C runtime marker 0xdddddddd of a deleted memory region.错误'utf-8' codec can't decode byte 0xdd提示。

curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)json_data.dump().size()));

curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, json_data.dump().c_str());

should fix the issue.应该解决这个问题。 Setting CURLOPT_POSTFIELDSIZE may be omitted, if the size has not been set prior to CURLOPT_COPYPOSTFIELDS , the data is assumed to be a null-terminated string - it is your case.可以省略设置CURLOPT_POSTFIELDSIZE ,如果在CURLOPT_COPYPOSTFIELDS之前没有设置大小,则假定数据是一个以空字符结尾的字符串 - 这是你的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM