You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinInet实现HTTPS请求时HttpSendRequest返回成功但无有效请求问题

问题排查与修复

核心问题分析

  • 字符集API混用:代码同时使用宽字符版本InternetOpenW和ANSI版本InternetConnect、HttpOpenRequest,WinInet要求同一会话内API字符集必须统一,参数解析错误会导致请求无法正确发送。
  • 错误处理逻辑错误:用perror处理WinInet错误是错误的,perror仅适用于POSIX系统调用,Win32 API错误需通过GetLastError()获取,这导致你误判HttpSendRequest执行成功,实际可能存在隐藏错误。
  • HTTPS证书验证拦截:WinInet默认严格验证SSL证书,若Flask服务器用自签名证书,WinInet会在握手阶段失败,请求无法到达服务器。
  • nc乱码的原因:nc收到的乱码是HTTPS加密后的正常流量,nc不支持SSL解密,因此无法显示明文。

修复步骤

1. 统一字符集API

将所有WinInet API改为宽字符版本,避免编码冲突:

void connect(LPCWSTR hostname, LPCWSTR endpoint)
{
    LPCWSTR userAgent = L"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0";
    HINTERNET hInternet = InternetOpenW(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hInternet == NULL) {
        printf("InternetOpenW failed, error: %lu\n", GetLastError());
        exit(EXIT_FAILURE);
    }

    HINTERNET hConnect = InternetConnectW(hInternet, hostname, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (hConnect == NULL) {
        printf("InternetConnectW failed, error: %lu\n", GetLastError());
        InternetCloseHandle(hInternet);
        exit(EXIT_FAILURE);
    }

    LPCWSTR accept[] = {L"application/json", NULL};
    // 添加证书忽略标志(仅测试环境使用)
    HINTERNET hRequest = HttpOpenRequestW(hConnect, L"POST", endpoint, L"HTTP/1.1", NULL, accept, 
        INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0);
    if (hRequest == NULL) {
        printf("HttpOpenRequestW failed, error: %lu\n", GetLastError());
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        exit(EXIT_FAILURE);
    }

    LPCWSTR headers = L"Content-Type: application/json\r\n";
    if (HttpAddRequestHeadersW(hRequest, headers, -1L, HTTP_ADDREQ_FLAG_ADD) == FALSE) {
        printf("HttpAddRequestHeadersW failed, error: %lu\n", GetLastError());
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        exit(EXIT_FAILURE);
    }

    std::wstring data = L"{\"sessionId\": \"importants.txt\", \"authToken\": \"Nothing Important Here.\"}";
    if (HttpSendRequestW(hRequest, NULL, -1L, (LPVOID)data.c_str(), data.length() * sizeof(wchar_t)) == FALSE) {
        printf("HttpSendRequestW failed, error: %lu\n", GetLastError());
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        exit(EXIT_FAILURE);
    }

    std::wstring response;
    wchar_t buffer[4096];
    DWORD bytesRead;
    while (InternetReadFile(hRequest, buffer, sizeof(buffer) - sizeof(wchar_t), &bytesRead) && bytesRead > 0) {
        buffer[bytesRead / sizeof(wchar_t)] = L'\0';
        response += buffer;
    }

    std::wcout << response << std::endl;

    // 按正确顺序关闭句柄:请求→连接→根会话
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);
}

2. 修正错误处理

替换所有perror为GetLastError()输出错误码,能精准定位API调用失败的具体原因,比如证书验证错误、连接超时等。

3. 处理Flask证书问题

  • 测试环境:代码中添加的INTERNET_FLAG_IGNORE_CERT_CN_INVALID和INTERNET_FLAG_IGNORE_CERT_DATE_INVALID可跳过自签名证书验证。
  • 生产环境:必须使用合法SSL证书,或在Wine中导入自签名证书到系统信任存储。

4. 调整句柄关闭顺序

原代码关闭句柄顺序错误,需先关闭请求句柄hRequest,再关闭连接句柄hConnect,最后关闭根会话句柄hInternet,避免资源泄漏或请求中断。

5. 编译命令保持不变

x86_64-w64-mingw32-g++ harvester.cpp -o harvester.exe -l wininet -static-libstdc++ -static-libgcc

额外注意事项

  • 若Flask服务器用HTTP而非HTTPS,需将端口改为80,移除所有SSL相关标志。
  • 生产环境禁止忽略证书验证,否则会引发安全风险。

内容的提问来源于stack exchange,提问作者Sayan Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:43:14