c++http客户端发送怎么写

就是我想用c++的http进行发送数据,比如说像http://127.0.0.1:7999/api/fun1发送数据,应该怎么写我看别人写的使用#include <wininet.h>,#include <json/json.h>这两个,代码

#include <windows.h>
#include <wininet.h>
#include <json/json.h>
#include <iostream>
using namespace Json;
#pragma comment(lib, "wininet.lib")

int main() {
    HINTERNET hInternet, hConnect;
    DWORD bytesRead;
    char buffer[4096];

    // 初始化WinINet库
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        std::cerr << "InternetOpenA failed!" << std::endl;
        return 1;
    }

    // 打开HTTP连接
    hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (hConnect == NULL) {
        std::cerr << "InternetOpenUrlA failed!" << std::endl;
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 构建JSON数据
    Json::Value jsonData;
    jsonData["key1"] = "value1";
    jsonData["key2"] = "value2";
    std::string postData = jsonData.toStyledString();

    // 发送POST数据
// 发送POST数据
    if (!InternetWriteFile(hConnect, postData.c_str(), postData.length(), &bytesRead)) {
        DWORD error = GetLastError();
        char errorBuffer[4096];
        DWORD bufferSize = sizeof(errorBuffer);
        if (InternetGetLastResponseInfoA(&error, errorBuffer, &bufferSize)) {
            std::cerr << "InternetWriteFile failed! Error: " << error << ", Response: " << errorBuffer << std::endl;
        }
        else {
            std::cerr << "InternetWriteFile failed! Error: " << error << std::endl;
        }
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }


    // 读取响应数据
    while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        // 在这里处理响应数据,例如打印到控制台
        std::cout.write(buffer, bytesRead);
    }

    // 关闭连接和WinINet库
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);

    return 0;
}

使用这个发送的时候,报错的是InternetWriteFile failed! Error,但是服务器那边接受到了数据,只是没有消息体,并且使用postman是可以发送成功的,应该怎么修改


#include <iostream>
#include <string>
#include <curl/curl.h>

size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *s) {
    size_t newLength = s->length() + size*nmemb;
    char *newStr = new char[newLength];
    delete[] s->data();
    s->assign(newStr, newLength);
    return size*nmemb;
}

int main(void) {
    CURL *curl;
    CURLcode res;
    std::string s = "";

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); // 修改为你的URL
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();

    std::cout << s << std::endl;
    return 0;
}

该回答引用chatgpt

以下是一个简单的 C++ HTTP 客户端示例代码,使用 cURL 库进行 HTTP 请求:

#include <iostream>
#include <curl/curl.h>

// 回调函数,处理 HTTP 响应
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response)
{
    size_t totalSize = size * nmemb;
    response->append((char*)contents, totalSize);
    return totalSize;
}

int main()
{
    CURL* curl;
    CURLcode res;
    std::string response;

    // 初始化 cURL
    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();

    if (curl)
    {
        // 设置请求的 URL
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");

        // 设置回调函数来处理响应数据
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

        // 执行 HTTP 请求
        res = curl_easy_perform(curl);

        // 检查是否请求成功
        if (res != CURLE_OK)
        {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        }
        else
        {
            // 打印响应数据
            std::cout << response << std::endl;
        }

        // 清理和释放资源
        curl_easy_cleanup(curl);
    }

    // 全局清理
    curl_global_cleanup();

    return 0;
}

请注意,这个示例使用了 cURL 库来进行 HTTP 请求。你需要先安装 cURL 库,并在编译时链接 cURL 库。此外,还需要包含 <curl/curl.h> 头文件。

这个示例的主要步骤包括初始化 cURL、设置请求的 URL、设置回调函数处理响应、执行 HTTP 请求、检查请求结果和清理资源。

这只是一个简单的示例,你可以根据自己的需求进行扩展和修改。同时,还可以使用其他的 C++ HTTP 客户端库来实现类似的功能,如 Boost.Beast、Poco C++ 库等。

希望对你有帮助!如果你还有其他问题,请随时提问。

引用chatgpt内容作答:
根据你提供的代码,出现错误的地方是在InternetWriteFile这一步。错误代码并没有具体说明问题,但你说服务器那边接收到了数据却没有消息体,这可能是因为你没有正确设置HTTP请求的头部信息,导致服务器无法正确解析请求。

以下是你可以尝试修改的地方:

在打开HTTP连接之前,设置正确的HTTP请求头部信息,特别是Content-Type和Content-Length。

HINTERNET hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", 
    "Content-Type: application/json\r\n", // Set the Content-Type header
    -1, INTERNET_FLAG_RELOAD, 0);

修改发送POST数据的方式,将数据放在请求消息体中。同时,你需要设置Content-Length头部以确保服务器正确读取请求体的长度。

std::string postData = jsonData.toStyledString();

if (!HttpSendRequestA(hConnect, "Content-Type: application/json\r\n",
                      -1, (LPVOID)postData.c_str(), postData.length())) {
    // Handle error
}

整合修改后的代码如下:

#include <windows.h>
#include <wininet.h>
#include <json/json.h>
#include <iostream>
using namespace Json;
#pragma comment(lib, "wininet.lib")
 
int main() {
    HINTERNET hInternet, hConnect;
    DWORD bytesRead;
    char buffer[4096];
 
    // 初始化WinINet库
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        std::cerr << "InternetOpenA failed!" << std::endl;
        return 1;
    }
 
    // 打开HTTP连接
    hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", 
        "Content-Type: application/json\r\n", -1, INTERNET_FLAG_RELOAD, 0);
    if (hConnect == NULL) {
        std::cerr << "InternetOpenUrlA failed!" << std::endl;
        InternetCloseHandle(hInternet);
        return 1;
    }
 
    // 构建JSON数据
    Json::Value jsonData;
    jsonData["key1"] = "value1";
    jsonData["key2"] = "value2";
    std::string postData = jsonData.toStyledString();
 
    // 发送POST数据
    if (!HttpSendRequestA(hConnect, "Content-Type: application/json\r\n",
                          -1, (LPVOID)postData.c_str(), postData.length())) {
        DWORD error = GetLastError();
        char errorBuffer[4096];
        DWORD bufferSize = sizeof(errorBuffer);
        if (InternetGetLastResponseInfoA(&error, errorBuffer, &bufferSize)) {
            std::cerr << "HttpSendRequestA failed! Error: " << error << ", Response: " << errorBuffer << std::endl;
        }
        else {
            std::cerr << "HttpSendRequestA failed! Error: " << error << std::endl;
        }
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }
 
    // 读取响应数据
    while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        // 在这里处理响应数据,例如打印到控制台
        std::cout.write(buffer, bytesRead);
    }
 
    // 关闭连接和WinINet库
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);
 
    return 0;
}

通过这些修改,你的代码应该能够正确地发送POST请求并获取响应了。记得根据你的实际情况修改请求的URL和JSON数据。如果服务器需要其他特定的头部信息或者参数,也要根据需要进行设置。

你随便用个http的开源库都比这个windows api的http好用,用的比较广泛的就是curl,你用vs开发的话nuget安装一下curl代码里就能用了

#include <windows.h>
#include <wininet.h>
#include <json/json.h>
#include <iostream>
using namespace Json;
#pragma comment(lib, "wininet.lib")

int main() {
    HINTERNET hInternet, hConnect, hRequest;
    DWORD bytesRead;
    char buffer[4096];

    // 初始化WinINet库
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        std::cerr << "InternetOpenA failed!" << std::endl;
        return 1;
    }

    // 打开HTTP连接
    hConnect = InternetConnectA(hInternet, "127.0.0.1", 7999, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (hConnect == NULL) {
        std::cerr << "InternetConnectA failed!" << std::endl;
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 创建HTTP请求
    hRequest = HttpOpenRequestA(hConnect, "POST", "/api/fun1", NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0);
    if (hRequest == NULL) {
        std::cerr << "HttpOpenRequestA failed!" << std::endl;
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 构建JSON数据
    Json::Value jsonData;
    jsonData["key1"] = "value1";
    jsonData["key2"] = "value2";
    std::string postData = jsonData.toStyledString();

    // 添加必要的HTTP请求头
    std::string headers = "Content-Type: application/json\r\n";
    HttpAddRequestHeadersA(hRequest, headers.c_str(), headers.length(), HTTP_ADDREQ_FLAG_ADD);

    // 发送POST数据
    if (!HttpSendRequestA(hRequest, NULL, 0, (LPVOID)postData.c_str(), postData.length())) {
        DWORD error = GetLastError();
        char errorBuffer[4096];
        DWORD bufferSize = sizeof(errorBuffer);
        if (InternetGetLastResponseInfoA(&error, errorBuffer, &bufferSize)) {
            std::cerr << "HttpSendRequestA failed! Error: " << error << ", Response: " << errorBuffer << std::endl;
        }
        else {
            std::cerr << "HttpSendRequestA failed! Error: " << error << std::endl;
        }
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 读取响应数据
    while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        // 在这里处理响应数据,例如打印到控制台
        std::cout.write(buffer, bytesRead);
    }

    // 关闭连接和WinINet库
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);

    return 0;
}

根据你给代码进行的修改使用了InternetConnectA函数创建HTTP连接,然后使用HttpOpenRequestA函数创建HTTP请求句柄,并指定了正确的HTTP方法(POST)。我们还添加了Content-Type: application/json的HTTP请求头,以确保服务器能够正确解析JSON数据。

援引GPT回答:
根据你提供的代码和描述,错误是在InternetWriteFile函数调用时发生的。这个错误可能是由于数据长度不正确或者请求未正确设置导致的。

首先,你需要确保postData中的数据长度是正确的。你可以使用strlen函数来获取字符串的长度,或者直接使用postData.size()来获取std::string对象的长度。

其次,你需要在InternetOpenUrlA函数调用时指定正确的请求方法和请求标志。根据你的描述,你想要发送POST请求,所以你可以将请求方法设置为"POST",请求标志设置为INTERNET_FLAG_RELOAD | INTERNET_FLAG_FORMS_SUBMIT。

修改后的代码如下:

#include <windows.h>
#include <wininet.h>
#include <json/json.h>
#include <iostream>
using namespace Json;
#pragma comment(lib, "wininet.lib")
 
int main() {
    HINTERNET hInternet, hConnect;
    DWORD bytesRead;
    char buffer[4096];
 
    // 初始化WinINet库
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        std::cerr << "InternetOpenA failed!" << std::endl;
        return 1;
    }
 
    // 打开HTTP连接
    hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_FORMS_SUBMIT, 0);
    if (hConnect == NULL) {
        std::cerr << "InternetOpenUrlA failed!" << std::endl;
        InternetCloseHandle(hInternet);
        return 1;
    }
 
    // 构建JSON数据
    Json::Value jsonData;
    jsonData["key1"] = "value1";
    jsonData["key2"] = "value2";
    std::string postData = jsonData.toStyledString();
 
    // 发送POST数据
    if (!InternetWriteFile(hConnect, postData.c_str(), postData.size(), &bytesRead)) {
        DWORD error = GetLastError();
        char errorBuffer[4096];
        DWORD bufferSize = sizeof(errorBuffer);
        if (InternetGetLastResponseInfoA(&error, errorBuffer, &bufferSize)) {
            std::cerr << "InternetWriteFile failed! Error: " << error << ", Response: " << errorBuffer << std::endl;
        }
        else {
            std::cerr << "InternetWriteFile failed! Error: " << error << std::endl;
        }
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }
 
    // 读取响应数据
    while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        // 在这里处理响应数据,例如打印到控制台
        std::cout.write(buffer, bytesRead);
    }
 
    // 关闭连接和WinINet库
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);
 
    return 0;
}

请注意,这只是一种可能的解决方案,具体的修改取决于你的服务器端要求和接口规范。你可能需要进一步调整代码以满足服务器端的要求。

【以下回答由 GPT 生成】

首先,你所提供的代码片段是使用WinINet库和JSON库来构建HTTP客户端发送数据的。以下是代码中的具体步骤:

  1. 导入所需的库文件: #include <windows.h> #include <wininet.h> #include <json/json.h> #include <iostream>

  2. 初始化WinINet库: HINTERNET hInternet, hConnect; // 初始化WinINet库 hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

  3. 打开HTTP连接: hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", NULL, 0, INTERNET_FLAG_RELOAD, 0);

  4. 构建JSON数据: Json::Value jsonData; jsonData["key1"] = "value1"; jsonData["key2"] = "value2"; std::string postData = jsonData.toStyledString();

  5. 发送POST数据: if (!InternetWriteFile(hConnect, postData.c_str(), postData.length(), &bytesRead)) { // 处理发送失败的情况 }

以上代码片段展示了如何使用WinINet库和JSON库来构建HTTP客户端发送数据。你可以根据你的需求进行修改和扩展。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

根据代码分析,问题可能出在发送POST数据部分。InternetWriteFile函数用于将数据写入到HTTP连接中,但是它可能无法正确处理非常长的数据。
在你的代码中,你使用了InternetWriteFile来发送POST数据。然而,对于非常长的数据,InternetWriteFile可能会失败。为了解决这个问题,可以尝试使用HttpSendRequest函数来代替InternetWriteFile。
以下是修改后的代码:

#include <windows.h>  
#include <wininet.h>  
#include <json/json.h>  
#include <iostream>  
using namespace Json;  
#pragma comment(lib, "wininet.lib")  
  
int main() {  
    HINTERNET hInternet, hConnect;  
    DWORD bytesRead;  
    char buffer[4096];  
    LPSTR headers = "Content-Type: application/json\r\n";  
  
    // 初始化WinINet库  
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);  
    if (hInternet == NULL) {  
        std::cerr << "InternetOpenA failed!" << std::endl;  
        return 1;  
    }  
  
    // 打开HTTP连接  
    hConnect = InternetOpenUrlA(hInternet, "http://127.0.0.1:7999/api/fun1", NULL, 0, INTERNET_FLAG_RELOAD, 0);  
    if (hConnect == NULL) {  
        std::cerr << "InternetOpenUrlA failed!" << std::endl;  
        InternetCloseHandle(hInternet);  
        return 1;  
    }  
  
    // 构建JSON数据  
    Json::Value jsonData;  
    jsonData["key1"] = "value1";  
    jsonData["key2"] = "value2";  
    std::string postData = jsonData.toStyledString();  
  
    // 发送POST数据  
    // 将POST数据转换为字节流并将其传递给HttpSendRequest函数  
    if (!HttpSendRequestA(hConnect, headers, -1, (LPVOID)postData.c_str(), postData.length())) {  
        DWORD error = GetLastError();  
        char errorBuffer[4096];  
        DWORD bufferSize = sizeof(errorBuffer);  
        if (InternetGetLastResponseInfoA(&error, errorBuffer, &bufferSize)) {  
            std::cerr << "HttpSendRequest failed! Error: " << error << ", Response: " << errorBuffer << std::endl;  
        }  
        else {  
            std::cerr << "HttpSendRequest failed! Error: " << error << std::endl;  
        }  
        InternetCloseHandle(hConnect);  
        InternetCloseHandle(hInternet);  
        return 1;  
    }  
  
    // 读取响应数据  
    while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {  
        // 在这里处理响应数据,例如打印到控制台  
        std::cout.write(buffer, bytesRead);  
    }  
  
    // 关闭连接和WinINet库  
    InternetCloseHandle(hConnect);  
    InternetCloseHandle(hInternet);  
  
    return 0;  
}


#如有帮助,恭请采纳

#include <iostream>
#include <curl/curl.h>
 
// 回调函数,处理 HTTP 响应
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response)
{
    size_t totalSize = size * nmemb;
    response->append((char*)contents, totalSize);
    return totalSize;
}
 
int main()
{
    CURL* curl;
    CURLcode res;
    std::string response;
 
    // 初始化 cURL
    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
 
    if (curl)
    {
        // 设置请求的 URL
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
 
        // 设置回调函数来处理响应数据
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
 
        // 执行 HTTP 请求
        res = curl_easy_perform(curl);
 
        // 检查是否请求成功
        if (res != CURLE_OK)
        {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        }
        else
        {
            // 打印响应数据
            std::cout << response << std::endl;
        }
 
        // 清理和释放资源
        curl_easy_cleanup(curl);
    }
 
    // 全局清理
    curl_global_cleanup();
 
    return 0;
}

看下这篇文章:https://blog.csdn.net/u012278016/article/details/106665722

看你的情况我猜测应该是没有加头,你的post request少了消息头。
把GetLastError();的值发出来,(可以参考对应的错误码去看原因),还有你的json请求结构体也发出来。

至少需要指定你的请求类型,最明显的,你的代码里都没有get和post相关的,你怎么确定你发的是post请求。
写入数据之前,一般要有个header,类似:

    char *bufSend = "Get /check?+参数 HTTP/1.1\r\n"  
        "Connection:Keep-Alive\r\n"
        "Accept-Encoding:gzip, deflate\r\n"  
        "Accept-Language:zh-CN,en,*\r\n"  
        "host:www.baidu.com\r\n" 
        "User-Agent:Mozilla/5.0\r\n\r\n";

还应指定内容的类型是Content-Type还是Content-len等等。
这里的api比较底层所以没封装类似setHeader这样的函数。像一些三方库里面,比如qt里面的HttpRequest,就可以设置header,可以看下这里。另外像java里面把这些都封装成各个函数了,比如

            //设置请求方法
            connection.setRequestMethod("POST");
            //设置参数类型
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

所以,你这里的http请求少了很多东西,请求行、请求头、请求数据方式等。

参考GPT回答:

  1. 错误代码:InternetWriteFile失败时,如果您使用了GetLastError函数获取错误代码,请查看返回的错误代码并按照相应的错误处理措施进行调整。

  2. 请求头:您的代码中没有给InternetOpenUrlA函数传递请求头参数,这可能会导致请求无法成功发送。尝试添加相应的请求头信息,例如设置"Content-Type"为"application/json"。

  3. 数据格式:您构建JSON数据并将其转换为字符串后,直接使用InternetWriteFile发送。但是,HTTP请求通常需要指定数据的长度。您可以尝试在发送之前添加请求头,指定Content-Length为字符串的长度。

  4. 转义字符:尝试对postData中的数据进行适当的转义,以确保它与服务器端预期的格式匹配。例如,在构建JSON数据时,如果您的数据中包含特殊字符(如引号),可以使用适当的转义字符。

你的代码在发送HTTP请求时出现了问题,尽管服务器接收到了请求,但没有消息体。。

首先,"InternetWriteFile failed! Error"错误可能有多种原因。

  1. 检查服务器端点和端口号:确保服务器端口号和端点路径/api/fun1正确。你可以在Postman中测试此端点,以确保它正常工作。

  2. 检查URL编码:请确保URL中的特殊字符已正确编码。使用InternetOpenUrlA函数时,URL需要是一个有效的ASCII字符串。如果URL包含非ASCII字符(如汉字),则需要进行URL编码。你可以使用C++的url_encode()函数编写一个帮助函数来进行URL编码。

  3. 检查权限和身份验证:确保你有足够的权限访问服务器端口号并发送请求。有些服务器可能需要进行身份验证,你可能需要提供相应的凭据。

  4. 检查HTTP头信息:在使用InternetOpenUrlA函数打开HTTP连接之前,你可以添加一些自定义的HTTP标头信息。这样,服务器就能正确解析请求。例如,你可以使用HttpAddRequestHeadersA函数添加Content-TypeAccept标头。


cpp

复制代码
#include <windows.h>
#include <wininet.h>
#include <json/json.h>
#include <iostream>
using namespace Json;
#pragma comment(lib, "wininet.lib")

std::string url_encode(const std::string& value) {
    std::ostringstream escaped;
    escaped.fill('0');
    escaped << std::hex;
    for (auto&& c : value) {
        // Keep alphanumeric and other accepted characters intact
        if (isalnum(static_cast<unsigned char>(c)) |
| c == '-' |
| c == '_' |
| c == '.' |
| c == '~') {
            escaped << c;
        }
        else {
            // Any other characters are percent-encoded
            escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
        }
    }
    return escaped.str();
}

int main() {
    HINTERNET hInternet, hConnect;
    DWORD bytesRead;
    char buffer[4096];

    // 初始化WinINet库
    hInternet = InternetOpenA("MyApp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        std::cerr << "InternetOpenA failed!" << std::endl;
        return 1;
    }

    // 构建URL
    std::string url = "http://127.0.0.1:7999/api/fun1";
    std::string postData = R"({"key1": "value1", "key2": "value2"})";
    std::string encodedPostData = url_encode(postData);
    url += "?data=" + encodedPostData;

    // 打开HTTP连接
    hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (hConnect == NULL) {
        std::cerr << "InternetOpenUrlA failed!" << std::endl;
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 读取响应数据
    while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
        // 在这里处理响应数据,例如打印到控制台
        std::cout.write(buffer, bytesRead);
    }

    // 关闭连接和WinINet库
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);

    return 0;
}


此示例代码对URL进行了修改,现在将POST数据编码为查询参数的一部分,并在打开连接时将其附加到URL上。有关如何使用url_encode()函数进行URL编码,请参考上面提供的示例。注意,此示例只是一种基本的URL编码方法,并且可能不支持某些字符。如果需要更全面的URL编码支持,请查找其他库或实施方案。

同时注意,此示例在构造URL时直接将JSON数据作为查询参数附加到URL上,这是为了示范目的,实际项目中你可能会将JSON数据放在请求体中发送。

希望这些修改能够解决你的问题!

C++发送HTTP请求的过程可以被分为以下几个步骤:

  1. 创建socket连接

HTTP是基于TCP/IP协议的,在发送HTTP请求之前,需要首先建立一个socket连接。在C++中,可以使用socket函数来创建一个socket连接。例如:

// 创建socket连接
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
    // 创建失败
    return -1;
}
  1. 构造HTTP请求报文

HTTP请求报文包括请求行、请求头和请求体三部分。

请求行:

请求行包括请求的方法、请求的URI和HTTP协议的版本。比如下面的请求行:

GET /index.html HTTP/1.1

请求头:

请求头包含了客户端发送给服务器的额外信息,比如Accept、User-Agent、Content-Type等等。比如下面的请求头:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Content-Type: application/x-www-form-urlencoded

请求体:

请求体是可选的,包含了客户端向服务器发送的数据。比如表单数据、JSON数据等等。

在C++中,可以使用stringstream来构造HTTP请求报文。例如:

// 构造请求行
std::stringstream request_stream;
request_stream << "GET " << url << " HTTP/1.1\r\n";

// 构造请求头
request_stream << "Host: " << host << "\r\n";
request_stream << "Connection: close\r\n";
request_stream << "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0\r\n";
request_stream << "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
request_stream << "Accept-Language: en-US,en;q=0.5\r\n";
request_stream << "Accept-Encoding: gzip, deflate\r\n";

// 构造请求体
request_stream << "\r\n";
  1. 解析URL

在构造HTTP请求报文中,需要解析URL获取其中的域名、端口和路径等信息。可以使用C++标准库中的regex来解析URL。例如:

std::regex url_regex("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)\\x3f?([^ #]*)#?([^ ]*)");
std::smatch match;
if (std::regex_match(url, match, url_regex)) {
    // 获取协议、域名、端口、路径和查询字符串
    std::string protocol = match[1].str();
    std::string host = match[2].str();
    std::string port = match[3].str().empty() ? (protocol == "https" ? "443" : "80") : match[3].str();
    std::string path = match[4].str();
    std::string query_string = match[5].str().empty() ? "" : "?" + match[5].str();
} else {
    // URL格式不正确
}
  1. 发送HTTP请求

在构造好HTTP请求报文后,需要使用socket连接向服务器发送HTTP请求。具体的发送过程可以使用send函数来完成。例如:

// 连接服务器
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(std::stoi(port));
inet_pton(AF_INET, host.c_str(), &server_addr.sin_addr);

if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
    // 连接失败
}

// 发送HTTP请求
send(sock, request_stream.str().c_str(), request_stream.str().length(), 0);
  1. 接收HTTP响应

发送完HTTP请求后,需要接收HTTP响应并解析其中的响应行、响应头和响应体。具体的接收过程可以使用recv函数来完成。例如:

// 接收HTTP响应
std::stringstream response_stream;
char buffer[1024];
int recvlen = 0;

do {
    recvlen = recv(sock, buffer, sizeof(buffer), 0);
    if (recvlen > 0) {
        response_stream.write(buffer, recvlen);
    }
} while (recvlen > 0);

// 解析响应头
std::string response = response_stream.str();
size_t pos = response.find("\r\n\r\n");
if (pos != std::string::npos) {
    std::string header_str = response.substr(0, pos + 4);
    std::string body_str = response.substr(pos + 4);

    // 解析响应行
    std::string line;
    std::stringstream header_stream(header_str);
    std::getline(header_stream, line);
    std::cout << line << std::endl;

    // 解析响应头
    while (std::getline(header_stream, line) && line != "\r") {
        std::cout << line << std::endl;
    }

    // 输出响应体
    std::cout << body_str << std::endl;
}

以上就是使用C++发送HTTP请求的基本过程。当然,实际应用中还需要对各种异常情况进行处理,比如连接超时、请求超时等等。