使用 winHttp 和 C++ 将 png 图像发送到服务器时失败

问题描述 投票:0回答:1

我是 winHttp 的新手,一直坚持将 png 图像作为附件发送到服务器。我使用 C++ 创建了一个 exe 只是为了解决这个问题。不知何故,我设法连接到服务器,它给出了以下响应,

{"code":"9999","message":"org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'attachment' is not present","cause":".","correlationID":"***-***-43f4-82b2-***","apiURL":"POST : /file/4856.png","origin":"PartMfgServer","timestamp":1704814609769}

这是我的BE代码,

@PostMapping(path = "/{fileName}",  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadFileFromServer(@RequestHeader("File-Type") String contentType,
                                   @PathVariable("fileName") String fileName,
                                   @RequestParam(value = "fileRole", required = false) FILE_ROLE fileRole,
                                   @RequestParam("attachment") MultipartFile fileToUpload) 
{.......}

这是我的代码,

int main() {
    LPCWSTR server = L"amn.dm-labs.com";
    LPCWSTR path = L"api/v2307/file/4856.png";

    HINTERNET hSession = WinHttpOpen(L"ImageUploader/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) {
        return -1;
    }

    HINTERNET hConnect = WinHttpConnect(hSession, server, INTERNET_DEFAULT_HTTPS_PORT, 0);
    if (!hConnect) {
        std::cerr << "WinHttpConnect failed!" << std::endl;
        WinHttpCloseHandle(hSession);
        return -1;
    }

    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
    if (!hRequest) {
        // Handle connection error
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    // Open image file for reading
    HANDLE hFile = CreateFile(L"C:\\Users\\m5zmfk\\AppData\\Local\\Temp\\nxOpen\\partfiles\\4856\\4856.png", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        // Handle file open error
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }


    DWORD fileSize = GetFileSize(hFile, NULL);
    std::wstring boundary = L"---------------------------1234567890";
 //   std::wstring endBoundary = L"\r\n--" + boundary + L"--\r\n";


    std::wstring formDataBody = L"--" + boundary + L"\r\n"
        L"Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n"
        L"\r\n--" + boundary + L"--\r\n";

    std::wstring headers = L"authorization: ****\r\n"
        L"Content-Type: multipart/form-data; boundary=" + boundary + L"\r\n"
        L"File-Type: image/png\r\n"
        L"Content-Length: " + std::to_wstring(fileSize + formDataBody.length()) +L"\r\n";

    bool success = WinHttpAddRequestHeaders(hRequest, headers.c_str(), headers.length(), WINHTTP_ADDREQ_FLAG_ADD);

    if (!success) {
        std::cout << "Error adding headers" << std::endl;
        printLastError(GetLastError());
    }

    DWORD timeout = 60000 * 2; // Set timeout to 60 seconds (adjust as needed)
    WinHttpSetOption(hRequest, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout));
    WinHttpSetOption(hRequest, WINHTTP_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout));

    if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
        // Handle request send error
        printLastError(GetLastError());
        CloseHandle(hFile);
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    DWORD bytesWritten;
    // Build the form-data request body
   
    success = WinHttpWriteData(hRequest, formDataBody.c_str(), formDataBody.length(), &bytesWritten);

    if (!success) {
        printLastError(GetLastError());
        CloseHandle(hFile);
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    // Write the file content
    BYTE buffer[1024];
    DWORD bytesRead;
    while (ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL) && bytesRead > 0) {
        success = WinHttpWriteData(hRequest, buffer, bytesRead, &bytesWritten);
        if (!success) {
            printLastError(GetLastError());
            CloseHandle(hFile);
            WinHttpCloseHandle(hRequest);
            WinHttpCloseHandle(hConnect);
            WinHttpCloseHandle(hSession);
            return -1;
        }
    }

    if (!WinHttpReceiveResponse(hRequest, NULL)) {
        // Handle response error
        printLastError(GetLastError());
        CloseHandle(hFile);
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    // Read and print the response
    DWORD resRead;
    BYTE resBuffer[1024];
    while (WinHttpReadData(hRequest, resBuffer, sizeof(resBuffer), &resRead) && resRead > 0) {
        // Process the received data (you can print it or save it to a file, etc.)
        std::cout.write(reinterpret_cast<const char*>(resBuffer), resRead);
    }

    // Close the file and WinHTTP handles
    CloseHandle(hFile);
    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    return 0;
}

任何人都可以帮我解决出什么问题吗?

我尝试使用

formDataBody
WinHttpAddRequestHeaders
作为标题。我收到错误代码 87。

 std::wstring formDataBody = L"--" + boundary + L"\r\n"
        L"Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n"
        L"\r\n--" + boundary + L"--\r\n";
c++ https http-headers winhttp winhttprequest
1个回答
0
投票

您没有正确发送 PNG 数据。它需要位于您的 formDataBody 变量内,作为标头之后、结束边界之前的

attachment
MIME 部分的主体。您试图在 MIME 数据之后发送 PNG 数据,这是错误的。
此外,

File-Type

不是可识别的 HTTP 标头。您需要在

Content-Type
MIME 部分包含
attachment
标头。
此外,MIME 基于 7 位 ASCII,因此您不应该对 

std::wstring

变量使用

formDataBody
,而应使用
std::string
(对 WinHTTP 调用使用
std::wstring
就可以了)。
尝试更多类似这样的事情:

bool readAll(HANDLE hFile, void *buffer, DWORD bufsize) { char *pBuffer = static_cast<char*>(buffer); DWORD dwNumRead; while (bufsize != 0) { if (!ReadFile(hFile, pBuffer, bufsize, &dwNumRead, NULL)) { return false; } pBuffer += dwNumRead; bufsize -= dwNumRead; } return true; } void printFailure(const char *funcName) { DWORD dwError = GetLastError(); std::cerr << funcName << " failed!" << std::endl; printLastError(dwError); } int main() { LPCWSTR server = L"amn.dm-labs.com"; LPCWSTR path = L"api/v2307/file/4856.png"; HANDLE hFile = CreateFile(L"C:\\Users\\m5zmfk\\AppData\\Local\\Temp\\nxOpen\\partfiles\\4856\\4856.png", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printFailure("CreateFile"); return -1; } DWORD fileSize = GetFileSize(hFile, NULL); if (fileSize == ERROR_INVALID_FILE_SIZE) { printFailure("GetFileSize"); CloseHandle(hFile); return -1; } std::string fileData; if (fileSize > 0) { fileData.resize(fileSize); if (!readAll(hFile, &fileData[0], fileSize)) { printFailure("ReadFile"); CloseHandle(hFile); return -1; } } CloseHandle(hFile); HINTERNET hSession = WinHttpOpen(L"ImageUploader/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) { printFailure("WinHttpOpen"); return -1; } HINTERNET hConnect = WinHttpConnect(hSession, server, INTERNET_DEFAULT_HTTPS_PORT, 0); if (!hConnect) { printFailure("WinHttpConnect"); WinHttpCloseHandle(hSession); return -1; } HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); if (!hRequest) { printFailure("WinHttpOpenRequest"); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return -1; } std::string sBoundary = "---------------------------1234567890"; std::wstring wBoundary = L"---------------------------1234567890"; std::string formDataBody = "--" + sBoundary + "\r\n" "Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n" "Content-Type: image/png\r\n" "\r\n" + sFileData + "\r\n" "--" + sBoundary + "--\r\n"; std::wstring headers = L"authorization: ****\r\n" L"Content-Type: multipart/form-data; boundary=" + wBoundary + L"\r\n" L"Content-Length: " + std::to_wstring(formDataBody.length()) + L"\r\n"; DWORD timeout = 60000 * 2; // Set timeout to 60 seconds (adjust as needed) WinHttpSetOption(hRequest, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout)); WinHttpSetOption(hRequest, WINHTTP_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout)); if (!WinHttpSendRequest(hRequest, headers.c_str(), headers.length(), formDataBody.c_str(), formDataBody.length(), formDataBody.length(), 0)) { printFailure("WinHttpSendRequest"); WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return -1; } if (!WinHttpReceiveResponse(hRequest, NULL)) { printFailure("WinHttpReceiveResponse"); WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return -1; } // Read and print the response DWORD resRead; char resBuffer[1024]; do { if (!WinHttpReadData(hRequest, resBuffer, sizeof(resBuffer), &resRead)) { printFailure("WinHttpReadData"); WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return -1; } if (resRead == 0) break; std::cout.write(resBuffer, resRead); } while (true); WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return 0; }

或者,如果您确实想使用 
WinHttpWriteData()

以块的形式发送 PNG 数据,那么它需要看起来更像这样:

void printFailure(const char *funcName) {
    DWORD dwError = GetLastError();
    std::cerr << funcName << " failed!" << std::endl;
    printLastError(dwError);
}

int main() {
    LPCWSTR server = L"amn.dm-labs.com";
    LPCWSTR path = L"api/v2307/file/4856.png";
    
    HANDLE hFile = CreateFile(L"C:\\Users\\m5zmfk\\AppData\\Local\\Temp\\nxOpen\\partfiles\\4856\\4856.png", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        printFailure("CreateFile");
        return -1;
    }

    DWORD fileSize = GetFileSize(hFile, NULL);
    if (fileSize == ERROR_INVALID_FILE_SIZE) {
        printFailure("GetFileSize");
        CloseHandle(hFile);
        return -1;
    }

    HINTERNET hSession = WinHttpOpen(L"ImageUploader/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) {
        printFailure("WinHttpOpen");
        CloseHandle(hFile);
        return -1;
    }

    HINTERNET hConnect = WinHttpConnect(hSession, server, INTERNET_DEFAULT_HTTPS_PORT, 0);
    if (!hConnect) {
        printFailure("WinHttpConnect");
        WinHttpCloseHandle(hSession);
        CloseHandle(hFile);
        return -1;
    }

    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
    if (!hRequest) {
        printFailure("WinHttpOpenRequest");
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        CloseHandle(hFile);
        return -1;
    }

    std::string sBoundary =   "---------------------------1234567890";
    std::wstring wBoundary = L"---------------------------1234567890";

    std::string formDataBody1 = "--" + sBoundary + "\r\n"
        "Content-Disposition: form-data; name=\"attachment\"; filename=\"4856.png\"\r\n"
        "Content-Type: image/png\r\n"
        "\r\n";

    std::string formDataBody2 = "\r\n"
        "--" + sBoundary + "--\r\n";

    DWORD dwTotalLength = formDataBody1.length() + fileSize + formDataBody2.length();
    DWORD dwBytesWritten;
    
    std::wstring headers = L"authorization: ****\r\n"
        L"Content-Type: multipart/form-data; boundary=" + wBoundary + L"\r\n";

    DWORD timeout = 60000 * 2; // Set timeout to 60 seconds (adjust as needed)
    WinHttpSetOption(hRequest, WINHTTP_OPTION_RECEIVE_TIMEOUT, &timeout, sizeof(timeout));
    WinHttpSetOption(hRequest, WINHTTP_OPTION_SEND_TIMEOUT, &timeout, sizeof(timeout));

    if (!WinHttpSendRequest(hRequest, headers.c_str(), headers.length(), WINHTTP_NO_REQUEST_DATA, 0, dwTotalLength, 0)) {
        printFailure("WinHttpSendRequest");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        CloseHandle(hFile);
        return -1;
    }

    if (!WinHttpWriteData(hRequest, formDataBody1.c_str(), formDataBody1.length(), &dwBytesWritten)) {
        printFailure("WinHttpWriteData");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        CloseHandle(hFile);
        return -1;
    }

    BYTE buffer[1024];
    DWORD bytesRead;

    do {
        if (!ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL)) {
            printFailure("ReadFile");
            WinHttpCloseHandle(hRequest);
            WinHttpCloseHandle(hConnect);
            WinHttpCloseHandle(hSession);
            CloseHandle(hFile);
            return -1;
        }
        
        if (bytesRead == 0)
            break;
            
        if (!WinHttpWriteData(hRequest, buffer, bytesRead, &bytesWritten)) {
            printFailure("WinHttpWriteData");
            WinHttpCloseHandle(hRequest);
            WinHttpCloseHandle(hConnect);
            WinHttpCloseHandle(hSession);
            CloseHandle(hFile);
            return -1;
        }
    }
    while (true);
    
    CloseHandle(hFile);

    if (!WinHttpWriteData(hRequest, formDataBody2.c_str(), formDataBody2.length(), &dwBytesWritten)) {
        printFailure("WinHttpWriteData");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        CloseHandle(hFile);
        return -1;
    }

    if (!WinHttpReceiveResponse(hRequest, NULL)) {
        printFailure("WinHttpReceiveResponse");
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    char resBuffer[1024];

    do {
        if (!WinHttpReadData(hRequest, resBuffer, sizeof(resBuffer), &bytesRead)) {
            printFailure("WinHttpReadData");
            WinHttpCloseHandle(hRequest);
            WinHttpCloseHandle(hConnect);
            WinHttpCloseHandle(hSession);
            return -1;
        }
        
        if (bytesRead == 0)
            break;
            
        std::cout.write(resBuffer, bytesRead);
    }
    while (true);

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    return 0;
}

© www.soinside.com 2019 - 2024. All rights reserved.