1. 程式人生 > >HTTP上傳檔案至伺服器

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}"}