HTTP使用 multipart/form-data 上傳多個字段(包括文件字節流 octet-stream)
阿新 • • 發佈:2017-09-21
sprintf logs pcs cer lpstr struct written all normal
自己用到的一個向服務器上傳多個字段的實例,代碼不全,僅做參考。
用的是WinINet,上傳的字段中包括文件字節流
/* PHttpRequest中自行組裝body之後,HttpSendRequest中自己判斷body長度時, 由於文件內容中存在 \0,所以body長度計算錯誤,導致上傳的文件內容不正確,直接指定body的長度也不行... PHttpRequest中未使用InternetWriteFile, */ int UpdateToServer2(stResumeInfo st, int& candId, CString& szUpdateTime, int& nFileSize) { HINTERNET hSession=0; HINTERNET hConnect=0; HINTERNET hRequest=0; DWORD dwNumberOfBytesWritten=0; DWORD dwBytesSend=0; DWORD dwFlag = 0; candId = 0; szUpdateTime.Empty(); hSession=InternetOpen(_T("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"), INTERNET_OPEN_TYPE_PRECONFIG,0, INTERNET_INVALID_PORT_NUMBER, 0); if (0==hSession) { LOG_INFO(L"----- updateResume InternetOpen return 0 !!! GetLastError: %d------", GetLastError()); return 0; } unsigned short port_ = INTERNET_DEFAULT_HTTP_PORT; if (CConfig::GetServerType() == 1) //外網用HTTPS { port_= INTERNET_DEFAULT_HTTPS_PORT; } hConnect=InternetConnect(hSession, CConfig::URL_HOST, port_, _T(""), _T(""), INTERNET_SERVICE_HTTP, 0, 0); //URL_HOST不能帶http:// if (0==hConnect) { InternetCloseHandle(hSession); LOG_INFO(L"----- updateResume InternetConnect return 0 !!! GetLastError: %d------", GetLastError()); return 0; } dwFlag=INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_UI ; if (CConfig::GetServerType() == 1) //外網用HTTPS dwFlag |= INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP ; #ifdef UP_FILE_TO_SEVER hRequest=HttpOpenRequest(hConnect, _T("POST"), RESUME_UPLOAD_URL, HTTP_VERSION, 0, 0, dwFlag, 0);//old #else hRequest=HttpOpenRequest(hConnect, _T("POST"), RESUME_UPLOAD_URL_NEW, HTTP_VERSION, 0, 0, dwFlag, 0); #endif if (0==hRequest) { InternetCloseHandle(hConnect); InternetCloseHandle(hSession); LOG_INFO(L"----- updateResume HttpOpenRequest return 0 !!! GetLastError: %d------", GetLastError()); return 0; } if (m_bCancel) return 0; //設置Header //TCHAR content_type[128]={0}; //_stprintf_s(content_type,TEXT("Content-Type: multipart/form-data; boundary=%s"), _T(ABOUNDARY)); CString content_type = TEXT("Content-Type: multipart/form-data; boundary="); content_type.Append(_T(ABOUNDARY)); HttpAddRequestHeaders(hRequest,content_type,-1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); //驗證cid和token CString szAuthorization = TEXT("Authorization: "); szAuthorization.Append(/*CA2T(s64, CP_UTF8)*/CBackstageManager::GetInstance().GetAuthorizationString()); HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); szAuthorization = TEXT("Agent-Info: "); szAuthorization.Append(CBackstageManager::GetInstance().GetAgentInfo()); HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); #ifdef UP_FILE_TO_SEVER //讀取文件內容和長度 HANDLE hFile; hFile=CreateFile(st.strFilePath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); DWORD dwFileSize=GetFileSize(hFile,0); BYTE* lpBuffer=(BYTE*)VirtualAlloc(0,dwFileSize,MEM_COMMIT,PAGE_READWRITE); if (0==lpBuffer) { InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hSession); LOG_INFO(L"----- updateResume VirtualAlloc return 0 !!! GetLastError: %d------", GetLastError()); return 0; } DWORD dwRead; ReadFile(hFile,lpBuffer,dwFileSize,&dwRead,0); CloseHandle(hFile); #endif char first_boundary[64]={0}; char delimiter[64]={0}; char end_boundary[64]={0}; sprintf_s(first_boundary,"--%s\r\n",ABOUNDARY); sprintf_s(delimiter,"\r\n--%s\r\n",ABOUNDARY); sprintf_s(end_boundary,"\r\n--%s--\r\n",ABOUNDARY); //LPSTR rn="\r\n"; //HTTP POST數據中的換行必須使用\r\n std::map<std::string, std::string> ssmap; GetResumeInfoMap(st, ssmap); ////上傳給後臺必須使用字符串,不能用整型 //計算body長度 char content_dispos[64]={0}; std::map<std::string, std::string>::iterator it = ssmap.begin(); int length = strlen(first_boundary); for(; it != ssmap.end(); it++) { memset(content_dispos, 0, sizeof(content_dispos)); sprintf_s(content_dispos,"Content-Disposition: form-data; name=\"%s\"\r\n\r\n", it->first.c_str()); length += strlen(content_dispos); length += it->second.length(); length += strlen(delimiter); } #ifdef UP_FILE_TO_SEVER char content_dispos2[256]={0}; CString stmName = st.file_name; if(stmName.GetLength() > 32) { stmName = stmName.Left(28) + PathFindExtension(stmName); //防止content_dispos2越界 } std::string name = CT2A(stmName, CP_UTF8); sprintf_s(content_dispos2, "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", name.c_str()); LPSTR content_type2="Content-Type: application/octet-stream\r\n\r\n"; //加上File長度 length +=dwFileSize + strlen(content_dispos2) +strlen(content_type2); #else length -= strlen(delimiter); #endif length += strlen(end_boundary); if (m_bCancel) return FALSE; INTERNET_BUFFERS BufferIn; BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); BufferIn.Next = NULL; BufferIn.lpcszHeader = NULL; BufferIn.dwHeadersLength = 0; BufferIn.dwHeadersTotal = 0; BufferIn.lpvBuffer = NULL; BufferIn.dwBufferLength = 0; BufferIn.dwBufferTotal = length; BufferIn.dwOffsetLow = 0; BufferIn.dwOffsetHigh = 0; if (!HttpSendRequestEx(hRequest,&BufferIn,0,0,0)) { InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hSession); LOG_INFO(L"----- updateResume HttpSendRequestEx return 0 !!! GetLastError: %d------", GetLastError()); return 0; } //上傳body InternetWriteFile(hRequest,(byte*)first_boundary,strlen(first_boundary),&dwNumberOfBytesWritten); //first boundary int count = ssmap.size(); std::map<std::string, std::string>::iterator iter = ssmap.begin(); for(int index = 0; iter != ssmap.end(); iter++, index++) { memset(content_dispos, 0, sizeof(content_dispos)); sprintf_s(content_dispos,"Content-Disposition: form-data; name=\"%s\"\r\n\r\n", iter->first.c_str()); InternetWriteFile(hRequest,(byte*)content_dispos, strlen(content_dispos),&dwNumberOfBytesWritten); std::string value = iter->second; InternetWriteFile(hRequest,(byte*)value.c_str(), value.length(), &dwNumberOfBytesWritten); #ifndef UP_FILE_TO_SEVER if(index != (count-1)) #endif InternetWriteFile(hRequest,(byte*)delimiter,strlen(delimiter),&dwNumberOfBytesWritten); } if (m_bCancel) return 0; #ifdef UP_FILE_TO_SEVER //上傳文件 InternetWriteFile(hRequest,(byte*)content_dispos2,strlen(content_dispos2),&dwNumberOfBytesWritten); InternetWriteFile(hRequest,(byte*)content_type2,strlen(content_type2),&dwNumberOfBytesWritten); InternetWriteFile(hRequest,lpBuffer,dwFileSize,&dwNumberOfBytesWritten); #endif //last boundary InternetWriteFile(hRequest,(byte*)end_boundary,strlen(end_boundary),&dwNumberOfBytesWritten); if(!HttpEndRequest(hRequest,0,0,0)) { int a = GetLastError(); HttpEndRequest(hRequest,0,0,0); } #ifdef UP_FILE_TO_SEVER VirtualFree(lpBuffer,0,MEM_RELEASE); #endif if (m_bCancel) return 0; //獲取返回數據 std::stringstream sstream; GetResponse(&sstream, hRequest, 5000); Json::Value root; Json::Reader reader; reader.parse(sstream.str(), root); int code = -1; if(!root["code"].isNull()) { code = root["code"].asInt(); //0表示成功, }if(!root["data"].isNull()) { Json::Value data = root["data"]; int userId = data["userId"].asInt(); candId = data["candId"].asInt(); int resumeId = data["resId"].asInt(); nFileSize = data["resSize"].asInt(); } InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hSession); return 0; }
HTTP使用 multipart/form-data 上傳多個字段(包括文件字節流 octet-stream)