formdata上传文件_关于multipart/formdata上传文件
最近在做一個(gè)文件上傳的開放接口,用到Content-Type: multipart/form-data這種請(qǐng)求類型,特地做了一些研究和記錄。
在最初的 http協(xié)議中,并沒有上傳文件方面的功能。RFC1867為 http協(xié)議添加了這個(gè)能力。常見的瀏覽器,如 Microsoft IE, Mozila, Opera, Chrome,Safari等都已經(jīng)支持。按照此規(guī)范將用戶指定的文件發(fā)送到服務(wù)器。服務(wù)器端的程序如 java等,可以按照此規(guī)范解析出用戶發(fā)送來的文件。
RFC1867定義的請(qǐng)求格式如下示例:
------ZcyOpenBoundaryEEpIo3GVWKVCPrX8Content-Disposition: form-data; name="_data_"Content-Type: text/plain; charset=UTF-8Content-Transfer-Encoding: 8bit{"fileName":"redis-use.png","bizCode":"1071"}------ZcyOpenBoundaryEEpIo3GVWKVCPrX8Content-Disposition: form-data; name="file"; filename="deaultFilename"Content-Type: application/octet-streamContent-Transfer-Encoding: binary???àJFIF??C $.' ",#(7),01444'9=82<.>342??C ?à22"????3!1Aa"Qq?á2BR#3¢±???? !13QA?ú???{?Z3??j?êμr??c?÷·μO ??K?¥Tv?êhíI§~2,oFT4é÷?ò???1¢Y?9 etúíD=T?a?1Mo :?~t?StY)vè°l|t??eaHù?=E>?¤R3μ3/?E?Tb??í §\6£O-J#4Y÷?Fà?h_E5aw¢§?g?÷1Vˉ/-?·?3nDT=9?òai ,x?S^2?x|êF2?D?H?ò?±}K;h×Zó????YDàx?Z4]?|àr_?-y??q4ó2FV?àá??ì\óˉá×%?6[=P?9l??cJc?;-2??'òPYè?5é?=′?%?·üFc?1%±?'SL?′í?8¢?y@zc^]?Tm8·Ss"é1?QwG?'t?á¢êQ?YμmáDyimcl?4§H35??l?p4=¥,·(íA~x?O~]êjWòa?ók-g??%?la&27?r[áL¤?ìr7|II?14?`Q^í,$¤gw9?(??ùY?StT??ìˉ¨]?WT??%bˉC]EVê?ot?:ùê|?,¨>?ìw¢?0K7£?.?:Tò${B0a 1E¢?U?éé??EQ ?ù...省略部分內(nèi)容...------ZcyOpenBoundaryEEpIo3GVWKVCPrX8--這里的"----ZcyOpenBoundaryEEpIo3GVWKVCPrX8"是規(guī)范中定義的boundary。http傳輸?shù)膬?nèi)容通過boundary進(jìn)行了分割,以--${boundary}開始,并以${boundary}--結(jié)尾。
明白了以上內(nèi)容,我們?cè)賮砜慈绾问褂胢ultipart/form-data進(jìn)行文件上傳。以HttpClient為例進(jìn)行說明,其他工具大同小異。首先想到的就是要配置 http請(qǐng)求頭信息中的Content-Type字段,沒錯(cuò),我們來看如何進(jìn)行設(shè)置:
httpPost.addHeader("Content-Type", "multipart/form-data; boundary=----ZcyOpenBoundaryEEpIo3GVWKVCPrX8");注意,這里multipart/form-data 后面要跟上boundary。當(dāng)然,我們也可以不進(jìn)行Content-Type設(shè)置,一般工具都會(huì)為我們自動(dòng)生成規(guī)范的Content-Type,自動(dòng)生成過程不在本次討論范圍內(nèi),讀者可以自行閱讀代碼。
繼續(xù),我們?cè)O(shè)置了請(qǐng)求頭中的boundary以后還要確保與代碼片段1中的boundary保持一致,否則服務(wù)端無法讀取到請(qǐng)求體信息。服務(wù)端正常情況下收到的請(qǐng)求是下面的樣子:
當(dāng)然,上圖是以Spring框架為例,其他框架或語言亦大同小異。
那么怎么保證請(qǐng)求頭中的boundary與代碼片段1中的boundary一致呢?一種辦法是模擬http請(qǐng)求手寫拼接報(bào)文:
String BOUNDARY = "----ZcyOpenBoundaryEEpIo3GVWKVCPrX8";StringBuffer?sb?=?new?StringBuffer();// 發(fā)送字段for(int?i=0;?i sb = sb.append("--"); sb = sb.append(BOUNDARY); sb = sb.append("\r\n"); sb = sb.append("Content-Disposition: form-data; name=\""+ props[i] + "\"\r\n\r\n"); sb = sb.append(URLEncoder.encode(values[i])); sb = sb.append("\r\n");}// 發(fā)送文件:sb = sb.append("--");sb = sb.append(BOUNDARY);sb = sb.append("\r\n");sb = sb.append("Content-Disposition: form-data; name=\"1\"; filename=\"1.txt\"\r\n");sb = sb.append("Content-Type: application/octet-stream\r\n\r\n");byte[] data = sb.toString().getBytes();byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();// 設(shè)置HTTP頭hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length + end_data.length));// 輸出output = client.openOutputStream();output.write(data);output.write(file);output.write(end_data);......當(dāng)然以上方式比較原始,容易出錯(cuò),我們更喜歡用高級(jí)語言。下面還是以HttpClient為例:
String?result?=?"";String?boundary?="----ZcyOpenBoundaryEEpIo3GVWKVCPrX8";try?(CloseableHttpClient httpClient = HttpClients.createDefault()){ String fileName = file.getName(); HttpPost httpPost = new HttpPost(url); //設(shè)置請(qǐng)求頭????httpPost.setHeader("Content-Type","multipart/form-data;?boundary="+boundary); MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.STRICT, boundary, Charset.defaultCharset()); ????...省略內(nèi)容... httpPost.setEntity(multipartEntity); // 執(zhí)行提交 HttpResponse response = httpClient.execute(httpPost); if (response.getStatusLine().getStatusCode() == 200) { //響應(yīng) HttpEntity responseEntity = response.getEntity();??????if?(responseEntity?!=?null)?{ // 將響應(yīng)內(nèi)容轉(zhuǎn)換為字符串 result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8")); } } } catch (IOException e) { e.printStackTrace();} catch (Exception e) { e.printStackTrace();}?System.out.println("result="?+ result);注意,上述代碼中除了設(shè)置header頭中的boundary外,還要同時(shí)設(shè)置MultipartEntity對(duì)象中的boundary,這樣就保持一致啦。
至此,服務(wù)端已經(jīng)可以獲取到期待已久的文件流信息了。
總結(jié)
以上是生活随笔為你收集整理的formdata上传文件_关于multipart/formdata上传文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【LeetCode笔记】剑指 Offer
- 下一篇: java 根据圆心计算圆弧上点的经纬度_