本人最近开发MFC项目需要利用HTTP协议,上传文件至服务器,需要以二进制传输,Content-Type类型为: multipart/form-data,注意需要定义相关边界开始和结束
利用WinInt开发包HTTP封装
//HTTP服务
CHttpConnection* m_pHC;
CHttpFile* m_pHF;
CInternetSession m_cis;
以下为上传文件相关代码:
#include
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}"}