如何在C++上使用WinHTTP进行HTTPS调用(POST请求)

How to make HTTPS calls (POST requests) using WinHTTP on C++?

本文关键字:调用 HTTPS POST 请求 进行 WinHTTP C++      更新时间:2023-10-16

我正在C++上编写程序,以便使用WinHTTP对Java Servlet进行调用(POST请求)。当我通过HTTP请求POST时,一切正常,当我通过HTTPS请求时就会出现问题。它向服务器发送空请求,但切断请求主体(但它有内容)

int sendPostRequest(char *pszPostData, LPCTSTR servletUrl, char* resultBuffer, ofstream &outputFile) {
    outputFile << "====================================== SENDING REEQUEST ======================================" << endl;
    HINTERNET hSession = WinHttpOpen(
        userAgent,
        WINHTTP_ACCESS_TYPE_NO_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);
    if (!hSession)
    {
        _tprintf(_TEXT("Failed to open WinHTTP session: %ldn"), GetLastError());
        outputFile << "Failed to open WinHTTP session: %ldn" << GetLastError() << endl;
        return NULL;
    }
    else {
        _tprintf(_TEXT("Oppening WinHTTP session successful: %ldn"), GetLastError());
        outputFile << "Oppening WinHTTP session successful: %ldn" << GetLastError() << endl;
    }
    HINTERNET hConnect = WinHttpConnect(
        hSession,
        serverIP,
        serverPort,
        0);
    if (!hConnect)
    {
        _tprintf(_TEXT("Failed to connect to server: %ldn"), GetLastError());
        outputFile << "Failed to connect to server: %ldn" << GetLastError() << endl;
        WinHttpCloseHandle(hSession);
        return NULL;
    }
    else {
        _tprintf(_TEXT("Connection to server successful: %ldn"), GetLastError());
        outputFile << "Connection to server successful: %ldn" << GetLastError() << endl;
    }
    _tprintf(_TEXT("Post data : %ldn"), pszPostData);
    outputFile << "Post data : %ldn" << pszPostData << endl;
    DWORD dwDataLen = strlen(pszPostData);
    HINTERNET hRequest = WinHttpOpenRequest(
        hConnect,
        _TEXT("POST"),
        servletUrl,
        NULL,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        WINHTTP_FLAG_REFRESH);
    if (!hRequest)
    {
        _tprintf(_TEXT("Failed to open request: %ldn"), GetLastError());
        outputFile << "Failed to open request: %ldn" << GetLastError() << endl;
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }
    else {
        _tprintf(_TEXT("Opening request successful: %ldn"), GetLastError());
        outputFile << "Opening request successful: %ldn" << GetLastError() << endl;
    }
    DWORD dwReqOpts = 0;
    DWORD dwSize = sizeof(DWORD);
    WinHttpSetOption(
        hRequest,
        WINHTTP_OPTION_SECURITY_FLAGS,
        &dwReqOpts,
        sizeof(DWORD));
    BOOL done = false;
    BOOL rc = WinHttpSendRequest(
        hRequest,
        contentTypeHeader,
        -1,
        (LPVOID)pszPostData,
        dwDataLen,
        dwDataLen,
        NULL);
    if (rc) {
        rc = WinHttpReceiveResponse(hRequest, NULL);
        _tprintf(_TEXT("Sending request successful: %ldn"), GetLastError());
        outputFile << "Sending request successful: %ldn" << GetLastError() << endl;
    }
    else
    {
        _tprintf(_TEXT("Send request failed: %ldn"), GetLastError());
        outputFile << "Send request failed: %ldn" << GetLastError() << endl;
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }
    // Get the status from the server
    DWORD dwCode = 0;
    if (rc)
    {
        rc = WinHttpQueryHeaders(
            hRequest,
            WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
            NULL,
            &dwCode,
            &dwSize,
            NULL);
    }
    if (dwCode != HTTP_STATUS_OK)
    {
        _tprintf(_TEXT("HTTP Request failed: %ldn"), dwCode);
        outputFile << "HTTP Request failed: %ldn" << dwCode << endl;
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
    }
    else
    {
        _tprintf(_TEXT("HTTP Request is ok: %ldn"), dwCode);
        outputFile << "HTTP Request is ok : %ldn" << dwCode << endl;
        // Keep reading from the remote server until there's nothing left to read
        DWORD dwBytesToBeRead = 0, dwBytesRead = 0;
        //char szBuffer[8192] = { 0 };
        //strcpy(resultBuffer, "");
        do
        {
            if (!WinHttpQueryDataAvailable(hRequest, &dwBytesToBeRead))
            {
                _tprintf(_TEXT("No data available from server? %ld"), GetLastError());
                outputFile << "No data available from server? %ld" << GetLastError() << endl;
                WinHttpCloseHandle(hRequest);
                WinHttpCloseHandle(hConnect);
                WinHttpCloseHandle(hSession);
                return -1;
            }
            if (!WinHttpReadData(
                hRequest,
                //szBuffer,
                resultBuffer,
                //sizeof(szBuffer),
                RESULT_BUFFER_SIZE,
                &dwBytesRead))
            {
                _tprintf(_TEXT("Failed to read data from server: %ld"), GetLastError());
                outputFile << "Failed to read data from server: %ld" << GetLastError() << endl;
                WinHttpCloseHandle(hRequest);
                WinHttpCloseHandle(hConnect);
                WinHttpCloseHandle(hSession);
                return -1;
            }
            if (dwBytesRead > 0)
            {
                //szBuffer[dwBytesRead] = 0;
                resultBuffer[dwBytesRead] = 0; // NULL-terminated returned buffer
            }
        } while (dwBytesRead > 0);
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return 0;
    }
    return -1;
}

其中pszPostData-请求体的内容,servletUrl-Servlet(端点)的url,resultBuffer-调用结果将写入该缓冲区,outputFile-日志文件。

那么,如何在不剪切请求正文的情况下进行HTTPS调用呢?

关于WinHttpSendRequest方法,在第二个参数插入:L"content-type:application/x-www-form-urlencoded"和第三个参数-1,根据w3。

它应该可以进行此更正。

另外,检查你的.php文件的编码,有一次给我带来了麻烦。

我今天遇到了这个问题,因为我面临着一个非常类似的问题。在WinHttpConnect()中,我将pswzServerName作为"example.com"发送。问题是,在Apache中,我强制将domain.com重定向到www.domain.com,并将http重定向到https。由于我在WinHttpConnect()中指定了example.com,此重定向导致未发送POST数据、内容长度标头错误和内容类型标头错误。

有两种解决方案,最后一种是最佳选择:

Removing my htaccess non-www to www and http to https redirect
OR
just changing `pswzServerName` to 'www.example.com' (including the www.) in WinHttpConnect()

花了很长时间试图弄清楚为什么winhttp不起作用,因为这很容易被忽视,所以希望它能帮助其他可能处境相同的人。

即使这是一个老问题,这也可能有所帮助:
WINHTTP_FLAG_SECURE添加到WinHttpOpenRequest中,它应该可以工作。

...
HINTERNET hRequest = WinHttpOpenRequest(
        hConnect,
        _TEXT("POST"),
        servletUrl,
        NULL,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        WINHTTP_FLAG_REFRESH+WINHTTP_FLAG_SECURE); /// Here
...