我是 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";
您没有正确发送 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;
}