如何使用multipart/form-data格式上傳檔案(POST請求時,資料是放在請求體內,而不是要求標頭內,在html協議中,用 “\r\n” 換行,而不是 “\n”)

來源:互聯網
上載者:User

標籤:ipa   a1429   技術   tip   handler   catch   htm   c_str   過程   

在網路編程過程中需要向伺服器上傳檔案。Multipart/form-data是上傳檔案的一種方式。

Multipart/form-data其實就是瀏覽器用表單上傳檔案的方式。最常見的情境是:在寫郵件時,向郵件後添加附件,附件通常使用表單添加,也就是用multipart/form-data格式上傳到伺服器。

表單形式上傳附件

具體的步驟是怎樣的呢?

首先,用戶端和伺服器建立串連(TCP協議)。

第二,用戶端可以向伺服器端發送資料。因為上傳檔案實質上也是向伺服器端發送請求。

第三,用戶端按照符合“multipart/form-data”的格式向伺服器端發送資料。

Multipart/form-data的格式是怎樣的呢?

既然Multipart/form-data格式就是瀏覽器用表單提交資料的格式,我們就來看看檔案經過瀏覽器編碼後是什麼樣子。

  

 

HTML表單

 

瀏覽器開啟的表單

 

點擊“Browse…”分別選擇“unknow.gif”和“unknow1.gif”檔案,點擊“submit”按紐後,檔案將被上傳到伺服器。

下面是伺服器收到的資料:

 

伺服器收到的資料

這是一個POST請求。所以資料是放在請求體內,而不是要求標頭內。

這行指出這個請求是“multipart/form-data”格式的,且“boundary”是 “---------------------------7db15a14291cce”這個字串。

不難想象,“boundary”是用來隔開表單中不同部分資料的。例子中的表單就有 2 部分資料,用“boundary”隔開。“boundary”一般由系統隨機產生,但也可以簡單的用“-------------”來代替。

實際上,每部分資料的開頭都是由"--" + boundary開始,而不是由 boundary 開始。仔細看才能發現下面的開頭這段字串實際上要比 boundary 多了個 “--”   

緊接著 boundary 的是該部分資料的描述。

接下來才是資料。

 

 

“GIF”gif格式圖片的檔案頭,可見,unknow1.gif確實是gif格式圖片。

在請求的最後,則是 "--" + boundary + "--" 表明表單的結束。

 

需要注意的是,在html協議中,用 “\r\n” 換行,而不是 “\n”。

下面的代碼片斷示範如何構造multipart/form-data格式資料,並上傳圖片到伺服器。

//---------------------------------------

// this is the demo code of using multipart/form-data to upload text and photos.

// -use WinInet APIs.

//

//

// connection handlers.

//

HRESULT hr;

HINTERNET m_hOpen;

HINTERNET m_hConnect;

HINTERNET m_hRequest;

//

// make connection.

//

...

//

// form the content.

//

std::wstring strBoundary = std::wstring(L"------------------");

std::wstring wstrHeader(L"Content-Type: multipart/form-data, boundary=");

wstrHeader += strBoundary;

HttpAddRequestHeaders(m_hRequest, wstrHeader.c_str(), DWORD(wstrHeader.size()), HTTP_ADDREQ_FLAG_ADD);

//

// "std::wstring strPhotoPath" is the name of photo to upload.

//

//

// uploaded photo form-part begin.

//

std::wstring strMultipartFirst(L"--");

strMultipartFirst += strBoundary;

strMultipartFirst += L"\r\nContent-Disposition: form-data; name=\"pic\"; filename=";

strMultipartFirst += L"\"" + strPhotoPath + L"\"";

strMultipartFirst += L"\r\nContent-Type: image/jpeg\r\n\r\n";

//

// "std::wstring strTextContent" is the text to uploaded.

//

//

// uploaded text form-part begin.

//

std::wstring strMultipartInter(L"\r\n--");

strMultipartInter += strBoundary;

strMultipartInter += L"\r\nContent-Disposition: form-data; name=\"status\"\r\n\r\n";

std::wstring wstrPostDataUrlEncode(CEncodeTool::Encode_Url(strTextContent));

// add text content to send.

strMultipartInter += wstrPostDataUrlEncode;

std::wstring strMultipartEnd(L"\r\n--");

strMultipartEnd += strBoundary;

strMultipartEnd += L"--\r\n";

//

// open photo file.

//

// ws2s(std::wstring)

// -transform "strPhotopath" from unicode to ansi.

std::ifstream *pstdofsPicInput = new std::ifstream;

pstdofsPicInput->open((ws2s(strPhotoPath)).c_str(), std::ios::binary|std::ios::in);

pstdofsPicInput->seekg(0, std::ios::end);

int nFileSize = pstdofsPicInput->tellg();

if(nPicFileLen == 0)

{

return E_ACCESSDENIED;

}

char *pchPicFileBuf = NULL;

try

{

pchPicFileBuf = new char[nPicFileLen];

}

catch(std::bad_alloc)

{

hr = E_FAIL;

}

if(FAILED(hr))

{

return hr;

}

pstdofsPicInput->seekg(0, std::ios::beg);

pstdofsPicInput->read(pchPicFileBuf, nPicFileLen);

if(pstdofsPicInput->bad())

{

pstdofsPicInput->close();

hr = E_FAIL;

}

delete pstdofsPicInput;

if(FAILED(hr))

{

return hr;

}

// Calculate the length of data to send.

std::string straMultipartFirst = CEncodeTool::ws2s(strMultipartFirst);

std::string straMultipartInter = CEncodeTool::ws2s(strMultipartInter);

std::string straMultipartEnd = CEncodeTool::ws2s(strMultipartEnd);

int cSendBufLen = straMultipartFirst.size() + nPicFileLen + straMultipartInter.size() + straMultipartEnd.size();

// Allocate the buffer to temporary store the data to send.

PCHAR pchSendBuf = new CHAR[cSendBufLen];

memcpy(pchSendBuf, straMultipartFirst.c_str(), straMultipartFirst.size());

memcpy(pchSendBuf + straMultipartFirst.size(), (const char *)pchPicFileBuf, nPicFileLen);

memcpy(pchSendBuf + straMultipartFirst.size() + nPicFileLen, straMultipartInter.c_str(), straMultipartInter.size());

memcpy(pchSendBuf + straMultipartFirst.size() + nPicFileLen + straMultipartInter.size(), straMultipartEnd.c_str(), straMultipartEnd.size());

//

// send the request data.

//

HttpSendRequest(m_hRequest, NULL, 0, (LPVOID)pchSendBuf, cSendBufLen)

 

http://www.pc6.com/infoview/Article_50285.html

如何使用multipart/form-data格式上傳檔案(POST請求時,資料是放在請求體內,而不是要求標頭內,在html協議中,用 “\r\n” 換行,而不是 “\n”)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.