HTTP上傳檔案至伺服器
本人最近開發MFC專案需要利用HTTP協議,上傳檔案至伺服器,需要以二進位制傳輸,Content-Type型別為: multipart/form-data,注意需要定義相關邊界開始和結束
利用WinInt開發包HTTP封裝
//HTTP服務
CHttpConnection* m_pHC;
CHttpFile* m_pHF;
CInternetSession m_cis;
以下為上傳檔案相關程式碼:
#include <afxinet.h>
CString MakeRequestHeaders(CString &strBoundary)//包頭
{
CString strFormat;
CString strData;
//二進位制檔案傳送Content-Type型別為: multipart/form-data
strFormat = _T("Content-Type: multipart/form-data;charset=UTF-8;boundary=%s\r\n");
strData.Format(strFormat, strBoundary);
return strData;
}
CString MakePreFileData( CString &strBoundary, CString &strFileName)
{
CString strFormat;
CString strData;
if(!strFileName.Compare(TEXT("ecg.txt")))//檔案一
{
strFormat += _T("\r\n");
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"ecg_file\"; filename=\"ecg.txt\"");
strFormat += _T("\r\n");
strFormat += _T("Content-Type: text/plain");
strFormat += _T("\r\n\r\n");
strData.Format(strFormat, strBoundary);
}
else if(!strFileName.Compare(TEXT("ppg.txt")))//檔案二
{
strFormat += _T("\r\n");
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"ppg_file\"; filename=\"ppg.txt\"");
strFormat += _T("\r\n");
strFormat += _T("Content-Type: text/plain");
strFormat += _T("\r\n\r\n");
strData.Format(strFormat, strBoundary);
}
return strData;
}
CString MakePostFileData(CString &strBoundary)
{
CString strFormat;
CString strData;
strFormat += _T("\r\n");
strFormat += _T("--%s--");
strFormat += _T("\r\n");
strData.Format(strFormat, strBoundary);
return strData;
}
BOOL PostEcgPpg(CString& strURL,const CString& strLocalPath)//傳送資料,strLocalPath為本地路徑
{
CString pcmnameecg = TEXT("ecg.txt");
CString pcmnameppg = TEXT("ppg.txt");
CString _mEcgFilePath = strLocalPath + pcmnameecg;
CString _mPpgFilePath = strLocalPath + pcmnameppg;
CFile fTrackEcg;
CFile fTrackPpg;
CString strHTTPBoundary;
CString strPreFileDataEcg;
CString strPreFileDataPpg;
CString strPostFileData;
DWORD dwTotalRequestLength;
DWORD dwChunkLength;
DWORD dwReadLength;
DWORD dwResponseLength;
TCHAR szError[MAX_PATH];
void* pBuffer;
LPSTR szResponse;
CString strResponse;
BOOL bSuccess = TRUE;
CString strDebugMessage;
//開啟上傳檔案
if (FALSE == fTrackEcg.Open(_mEcgFilePath, CFile::modeRead | CFile::shareDenyWrite))
{
AfxMessageBox(_T("Unable to open the file."));
return FALSE;
}
if (FALSE == fTrackPpg.Open(_mPpgFilePath, CFile::modeRead | CFile::shareDenyWrite))
{
AfxMessageBox(_T("Unable to open the file."));
return FALSE;
}
//定義邊界值
strHTTPBoundary = _T("---------------------------7b4a6d158c9boundary");
strPreFileDataEcg = MakePreFileData(strHTTPBoundary,pcmnameecg);
strPreFileDataPpg = MakePreFileData(strHTTPBoundary,pcmnameppg);
strPostFileData = MakePostFileData(strHTTPBoundary);
//包總長度
dwTotalRequestLength = strPreFileDataEcg.GetLength() + strPreFileDataPpg.GetLength()
+ strPostFileData.GetLength() + fTrackEcg.GetLength() + fTrackPpg.GetLength();//計算整個包的總長度
dwChunkLength = 64 * 1024;
pBuffer = malloc(dwChunkLength);
if (NULL == pBuffer)
{
return FALSE;
}
try
{
m_pHC = m_cis.GetHttpConnection(m_ServerName,m_nPort);// IP地址和埠
m_pHF = m_pHC->OpenRequest(CHttpConnection::HTTP_VERB_POST, strURL);
//傳送包頭請求
m_pHF->AddRequestHeaders(MakeRequestHeaders(strHTTPBoundary));
m_pHF->AddRequestHeaders(TEXT("Accept-Encoding: gzip"));
m_pHF->AddRequestHeaders(TEXT("Connection: close"));
m_pHF->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE);
USES_CONVERSION;
//寫入伺服器所需資訊
#ifdef _UNICODE
m_pHF->Write(W2A(strPreFileDataEcg), strPreFileDataEcg.GetLength());
#else
m_pHF->Write((LPSTR)(LPCSTR)strPreFileDataEcg, strPreFileDataEcg.GetLength());
#endif
dwReadLength = -1;
while (0 != dwReadLength)
{
strDebugMessage.Format(_T("%u / %u\n"), fTrackEcg.GetPosition(), fTrackEcg.GetLength());
TRACE(strDebugMessage);
//讀取檔案內容
dwReadLength = fTrackEcg.Read(pBuffer, dwChunkLength);
if (0 != dwReadLength)
{
//寫入伺服器本地檔案,用二進位制進行傳送
m_pHF->Write(pBuffer, dwReadLength);
}
}
//寫入伺服器所需資訊
#ifdef _UNICODE
m_pHF->Write(W2A(strPreFileDataPpg), strPreFileDataPpg.GetLength());
#else
m_pHF->Write((LPSTR)(LPCSTR)strPreFileDataPpg, strPreFileDataPpg.GetLength());
#endif
dwReadLength = -1;
while (0 != dwReadLength)
{
strDebugMessage.Format(_T("%u / %u\n"), fTrackPpg.GetPosition(), fTrackPpg.GetLength());
TRACE(strDebugMessage);
//讀取檔案內容
dwReadLength = fTrackPpg.Read(pBuffer, dwChunkLength);
if (0 != dwReadLength)
{
//寫入伺服器本地檔案,用二進位制進行傳送
m_pHF->Write(pBuffer, dwReadLength);
}
}
#ifdef _UNICODE
m_pHF->Write(W2A(strPostFileData), strPostFileData.GetLength());
#else
m_pHF->Write((LPSTR)(LPCSTR)strPostFileData, strPostFileData.GetLength());
#endif
m_pHF->EndRequest(HSR_SYNC);
RecvProc(strResponse);
AfxMessageBox(strResponse);
}
catch (CException* e)
{
e->GetErrorMessage(szError, MAX_PATH);
e->Delete();
AfxMessageBox(szError);
bSuccess = FALSE;
}
m_pHF->Close();
delete m_pHF;
fTrackPpg.Close();
fTrackEcg.Close();
if (NULL != pBuffer)
{
free(pBuffer);
}
return bSuccess;
}
以下為上傳檔案相關抓包資訊:
請求頭資訊:
(Request-Line):POST /MiddleWare//measure/uploadEcgPpg?params=%7B%22memberId%22:26029%2C%22param%22:%7B%22deviceCode%22:%22%22%2C%22ppgFs%22:60%2C%22measureTime%22:%2220150901171440%22%2C%22ecgFs%22:250%2C%22spo%22:97%2C%22bluetoothMacAddr%22:%22%22%2C%22timeLength%22:0%7D%2C%22loginLog%22:%222015%2D09%2D01+17:14:40%22%2C%22session%22:%22f91dc047%2D90fb%2D4347%2D9991%2D3de54d29e111%22%2C%22version%22:%22v1%2E0%22%7D
HTTP/1.1
Content-Type:multipart/form-data;charset=UTF-8;boundary=---------------------------7b4a6d158c9boundary
Accept-Encoding:gzip
Connection:Close
User-Agent:HRPFBO
Host:192.168.11.22:8888
Content-Length:28478
Cache-Control:no-cache
響應頭資訊:
(Status-Line):HTTP/1.1 200 OK
Server:Apache-Coyote/1.1
Content-Type:text/html;charset=UTF-8
Content-Length:74
Date:Tue, 01 Sep 2015 09:15:10 GMT
Connection:close
請求傳送流:
POST /MiddleWare//measure/uploadEcgPpg?params=%7B%22memberId%22:26029%2C%22param%22:%7B%22deviceCode%22:%22%22%2C%22ppgFs%22:60%2C%22measureTime%22:%2220150901171440%22%2C%22ecgFs%22:250%2C%22spo%22:97%2C%22bluetoothMacAddr%22:%22%22%2C%22timeLength%22:0%7D%2C%22loginLog%22:%222015%2D09%2D01+17:14:40%22%2C%22session%22:%22f91dc047%2D90fb%2D4347%2D9991%2D3de54d29e111%22%2C%22version%22:%22v1%2E0%22%7D
HTTP/1.1
Content-Type: multipart/form-data;charset=UTF-8;boundary=---------------------------7b4a6d158c9boundary
Accept-Encoding: gzip
Connection: Close
User-Agent: HRPFBO
Host: 192.168.11.22:8888
Content-Length: 28478
Cache-Control: no-cache
-----------------------------7b4a6d158c9boundary
Content-Disposition: form-data; name="ecg_file"; filename="ecg.txt"
Content-Type: text/plain
ffffff41ffffff41ffffff41ffffff41ffffff40ffffff40ffffff3fffffff41ffffff41ffffff40ffffff41ffffff3bffffff40ffffff41ffffff41ffffff41ffffff41ffffff41ffffff41ffffff40ffffff41ffffff41ffffff41ffffff41ffffff41ffffff41ffffff41ffffff41ffffff40ffffff41ffffff4
-----------------------------7b4a6d158c9boundary
Content-Disposition: form-data; name="ppg_file"; filename="ppg.txt"
Content-Type: text/plain
7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f3
-----------------------------7b4a6d158c9boundary--
響應傳送流:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Content-Length: 74
Date: Tue, 01 Sep 2015 09:15:10 GMT
Connection: close
{"message":"成功","state":0,"content":"{\"ecg_id\":394,\"ppg_id\":319}"}