在 C/C++ 中发出 libcurl json post 请求
Making libcurl json post request in C/C++
我正在编写一个 Qt 应用程序,并且我有一个用于注册用户的按钮。我正在使用以下库:
- https://github.com/nlohmann/json <- json
serialization/deserialization
- libcurl
我的目标是能够向以下端点发出 post 请求:
http://localhost:8000/api/register
它需要 POST 的内容类型:application/json,utf-8,json 正文如下:
{
"username": "test",
"password": "test"
}
post 请求通过,但响应出错。我正在尝试确定这是我的 libcurl 代码的问题,还是我的 python django 应用程序的错误。
这是 libcurl 代码的详细输出:
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)
这是 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 一个 std::string 的范围取决于您是否在开发构建中。在开发构建期间,它始终通过 localhost,在发布构建中,它通过实时网络 url.
有人知道我这里可能做错了什么吗?
第一个错误在行 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str()));
中。 sizeof
并没有按照您的预期去做。
还有一个错误是 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str());
行存储了一个
指向临时数据 json_data.dump()
内部的指针,它会导致未定义的行为,可能会发送垃圾。错误 'utf-8' codec can't decode byte 0xdd
提示有关已删除内存区域的 Microsoft C 运行时标记 0xdddddddd。
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)json_data.dump().size()));
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, json_data.dump().c_str());
应该可以解决这个问题。设置 CURLOPT_POSTFIELDSIZE
可以省略,如果在 CURLOPT_COPYPOSTFIELDS
之前未设置大小,则数据被假定为 null-terminated 字符串 - 这是您的情况。
我正在编写一个 Qt 应用程序,并且我有一个用于注册用户的按钮。我正在使用以下库:
- https://github.com/nlohmann/json <- json serialization/deserialization
- libcurl
我的目标是能够向以下端点发出 post 请求: http://localhost:8000/api/register
它需要 POST 的内容类型:application/json,utf-8,json 正文如下:
{
"username": "test",
"password": "test"
}
post 请求通过,但响应出错。我正在尝试确定这是我的 libcurl 代码的问题,还是我的 python django 应用程序的错误。
这是 libcurl 代码的详细输出:
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)
这是 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 一个 std::string 的范围取决于您是否在开发构建中。在开发构建期间,它始终通过 localhost,在发布构建中,它通过实时网络 url.
有人知道我这里可能做错了什么吗?
第一个错误在行 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str()));
中。 sizeof
并没有按照您的预期去做。
还有一个错误是 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str());
行存储了一个
指向临时数据 json_data.dump()
内部的指针,它会导致未定义的行为,可能会发送垃圾。错误 'utf-8' codec can't decode byte 0xdd
提示有关已删除内存区域的 Microsoft C 运行时标记 0xdddddddd。
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)json_data.dump().size()));
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, json_data.dump().c_str());
应该可以解决这个问题。设置 CURLOPT_POSTFIELDSIZE
可以省略,如果在 CURLOPT_COPYPOSTFIELDS
之前未设置大小,则数据被假定为 null-terminated 字符串 - 这是您的情况。