http上传文件 pda java_通过HTTP协议上传文件
HTTP是很常見的協(xié)議,雖然用得很多,但對(duì)細(xì)節(jié)的了解卻是很淺,這回通過向服務(wù)端上傳文件信息來理解細(xì)節(jié)。網(wǎng)絡(luò)庫的選擇:1、WinHTTP是windows下常用的庫;2、CURL是廣受喜愛的開源庫。對(duì)于我來說,libcurl最大的優(yōu)點(diǎn)是使用方便,可以把注意力更多的集中到業(yè)務(wù)層上,提高工作效率,避免重造輪子;缺點(diǎn)是略大(MD編譯有264KB,MT編譯有340KB),不像WinHTTP可以由windows操作系統(tǒng)集成。下邊展示如何使用這兩種網(wǎng)絡(luò)庫實(shí)現(xiàn)表單POST文件。
一、libcurl
庫編譯:把include、lib的代碼拿出來,使用靜態(tài)庫,設(shè)置預(yù)定義宏BUILDING_LIBCURL。
測試工程:設(shè)置預(yù)定義宏CURL_STATICLIB;添加依賴lib:Ws2_32.lib Wldap32.lib。
主要代碼:
voidcurl_post_cswuyg()
{
curl_global_init(CURL_GLOBAL_ALL);
CURL* hCurl =curl_easy_init();if(hCurl !=NULL)
{//也許有Expect: 100-continue,去掉它
curl_slist* pOptionList =NULL;
pOptionList= curl_slist_append(pOptionList, "Expect:");
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, pOptionList);
curl_httppost* pFormPost =NULL;
curl_httppost* pLastElem =NULL;//上傳文件,指定本地文件完整路徑
curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "ufile01", CURLFORM_FILE, "C:\\temp\\upload_test_curl_cswuyg.txt", CURLFORM_CONTENTTYPE, "application/octet-stream", CURLFORM_END);//上傳自定義文件內(nèi)容的文件,CURLFORM_BUFFER指定服務(wù)端文件名//http://curl.haxx.se/libcurl/c/curl_formadd.html
char* file_info = "file_info——cswuyg";int record_length = std::string(file_info).length();
curl_formadd(&pFormPost, &pLastElem,
CURLFORM_COPYNAME,"ufile01",
CURLFORM_BUFFER,"cswuyg_test.txt",
CURLFORM_BUFFERPTR, file_info,
CURLFORM_BUFFERLENGTH, record_length,
CURLFORM_END);//不加一個(gè)結(jié)束的hfs服務(wù)端無法寫入文件,一般不存在這種問題,這里加入只是為了測試.//curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "end", CURLFORM_COPYCONTENTS, "end", CURLFORM_END);
curl_easy_setopt(hCurl, CURLOPT_HTTPPOST, pFormPost);
curl_easy_setopt(hCurl, CURLOPT_URL,"http://127.0.0.1/hfs_up/");
CURLcode res=curl_easy_perform(hCurl);if(res !=CURLE_OK)
{
std::wcout<< "Error" <<:endl>
}
curl_formfree(pFormPost);
curl_easy_cleanup(hCurl);
}
curl_global_cleanup();
}
wireshark抓包,127.0.0.1地址無法抓到,網(wǎng)絡(luò)上有解決方案。示意圖:
頭域設(shè)置分割符:
MIME部分:
二、WinHTTP
庫:winhttp.lib
主要代碼:
voidcswuyg_winhttp_post()
{
HINTERNET hSession= ::WinHttpOpen(L"cswuyg post test/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, NULL);
HINTERNET hConnect= ::WinHttpConnect(hSession, L"127.0.0.1", INTERNET_DEFAULT_HTTP_PORT, 0);if (hConnect ==NULL)
{int i =ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;return;
}const wchar_t* lpszAcceptedType[] = {L"*/*", NULL};
HINTERNET hRequest= ::WinHttpOpenRequest(hConnect, L"POST", L"hfs_up", L"HTTP/1.1", WINHTTP_NO_REFERER, lpszAcceptedType, 0);if (hRequest ==NULL)
{return;
}
DWORD dwTime= 5000;
::WinHttpSetOption(hRequest, WINHTTP_OPTION_CONNECT_TIMEOUT,&dwTime, sizeof(DWORD));
std::wstring strHeader= L"Content-Type: multipart/form-data; boundary=--boundary_cswuygtest\r\n";
::WinHttpAddRequestHeaders(hRequest, strHeader.c_str(), strHeader.length(), WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_REPLACE);
std::string strMIME = "----boundary_cswuygtest\r\n";
strMIME+= "Content-Disposition: form-data; name=\"ufile01\"; filename=\"upload_test_http_cswuyg.txt\"\r\n";
strMIME+= "Content-Type:application/octet-stream\r\n\r\n";
strMIME+= "1\r\n";/
//除了這個(gè)表單之外,后頭還必須要有另外的表單信息,否則hfs服務(wù)端那邊無法寫入文件,這里僅為測試。//strMIME += "----boundary_cswuygtest\r\n" ;//strMIME += "Content-Disposition: form-data; name=\"name\"\r\n\r\n";//strMIME += "temp.txt\r\n";
/
strMIME += "----boundary_cswuygtest--\r\n";/
//可以直接寫入//::WinHttpSendRequest(hRequest, strHeader.c_str(), strHeader.length(), (LPVOID)strMIME.c_str(), strMIME.length(), strMIME.length(), 0);//也可以后面分步寫入
::WinHttpSendRequest(hRequest, NULL, 0, NULL, 0, strMIME.length(), 0);
DWORD dwWritten= 0;while(!strMIME.empty())
{
::WinHttpWriteData(hRequest, strMIME.c_str(), strMIME.length(),&dwWritten);if (strMIME.length() >dwWritten)
{
strMIME.substr(dwWritten);
}else{
strMIME= "";
}
}
::WinHttpReceiveResponse(hRequest, NULL);char buf[1024] = { 0};
DWORD dwToRead= 1024;
DWORD dwHaveRead= 0;
::WinHttpReadData(hRequest, buf, dwToRead,&dwHaveRead);
std::cout<< buf <<:endl>
::WinHttpCloseHandle(hRequest);
::WinHttpCloseHandle(hConnect);
::WinHttpCloseHandle(hSession);
}
wireshark抓包:
頭域設(shè)置:
表單設(shè)置:
三、總結(jié)
這兩個(gè)例子用hfs做服務(wù)器測試可以發(fā)現(xiàn)在上傳文件夾中上傳了文件,代碼都很簡單。測試過程中的最重要的是能盡快的反饋結(jié)果,所以能自己搭建一個(gè)http服務(wù)器很重要,hfs工具,非常簡單便捷。
POST表單最重要的是了解表單的格式。首先要在頭域增加Content-Type說明,如:“content-type:multipart/from-data; boundary=--cswuyg”。然后http body填充的數(shù)據(jù)要以MIME格式上傳,每部分?jǐn)?shù)據(jù)的開頭都是由“--”+boundary開始的,結(jié)尾以"--"+boundary+"--"結(jié)束。
如果要上傳文件,需要跟服務(wù)器約定好格式,譬如上邊例子約定在content-Disposition中有filename鍵的則是上傳文件信息,該片的content為文件數(shù)據(jù),這應(yīng)該是比較通用的約定。
附上部分資料:
MIME:http://baike.baidu.com/view/160611.htm
MIME來源 : Multipurpose Internet Mail Extensions 多用途互聯(lián)網(wǎng)郵件擴(kuò)展。服務(wù)器會(huì)將它們發(fā)送的多媒體數(shù)據(jù)的類型告訴瀏覽器,而通知手段就是說明該多媒體數(shù)據(jù)的MIME類型。
GZIP文件:application/x-gzip
任意的二進(jìn)制數(shù)據(jù):application/octet-stream.
普通文本:text/plain
wireshark:
MIME Multipart Media Encapsulation 代表使用表單上傳的所有數(shù)據(jù)
Encapsulated multipart part 代表表單中不同項(xiàng)的數(shù)據(jù)
Boundary 用來隔開表單中不同部分的數(shù)據(jù)
每部分?jǐn)?shù)據(jù)的開頭都是由“--”+boundary開始的。
如果使用wireshark抓包,而http使用的不是默認(rèn)的80端口,那么需要抓TCP包,然后再強(qiáng)制Decode為http。
HTTP協(xié)議的文檔:
chroimumde breakpad_sender代碼中也有post表單上傳文件部分,只不過它是用WinInet寫的。
2015 補(bǔ)充上傳文件時(shí)的抓包信息:
總結(jié)
以上是生活随笔為你收集整理的http上传文件 pda java_通过HTTP协议上传文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10+GeForce 940mx安
- 下一篇: 锤子手机跑分数据曝光