multipart form-data boundary 說明(詳盡解釋)

來源:互聯網
上載者:User

原文轉自:http://yefeng.iteye.com/blog/315847

含義 ENCTYPE="multipart/form-data" 說明: 

通過 http 協議上傳檔案 rfc1867協議概述,jsp 應用舉例,用戶端發送內容構造 

1、概述在最初的 http 協議中,沒有上傳檔案方面的功能。 rfc1867 (http://www.ietf.org/rfc/rfc1867.txt) 為 http 協議添加了這個功能。用戶端的瀏覽器,如 Microsoft IE, Mozila, Opera 等,按照此規範將使用者指定的檔案發送到伺服器。伺服器端的網頁程式,如 php, asp, jsp 等,可以按照此規範,解析出使用者發送來的檔案。Microsoft IE, Mozila, Opera 已經支援此協議,在網頁中使用一個特殊的 form 就可以傳送檔案。絕大部分
http server ,包括 tomcat ,已經支援此協議,可接受發送來的檔案。各種網頁程式,如 php, asp, jsp 中,對於上傳檔案已經做了很好的封裝。 

2、上傳檔案的執行個體:用 servelet 實現(http server 為 tomcat 4.1.24)1. 在一個 html 網頁中,寫一個如下的form : 

<form enctype="multipart/form-data" action="http://192.168.29.65/UploadFile" method=post>  
load multi files :<br>    
<input name="userfile1" type="file"><br>   
<input name="userfile2" type="file"><br> 
<input name="userfile3" type="file"><br>    <input name="userfile4" type="file"><br>   
text field :<input type="text" name="text" value="text"><br>   
<input type="submit" value="提交"><input type=reset></form> 

使用者可以選擇多個檔案,填寫表單其它項,點擊“提交”按鈕後就開始上傳給 http://192.168.29.65/upload_file/UploadFile 

這是一個 servelet 程式注意 enctype="multipart/form-data", method=post, type="file" 。根據 rfc1867, 這三個屬性是必須的。multipart/form-data 是新增的編碼類別型,以提高二進位檔案的傳輸效率。具體的解釋請參閱 rfc18672. 服務端 servelet 的編寫現在第三方的 http upload file 工具庫很多。Jarkata 項目本身就提供了fileupload 包http://jakarta.apache.org/commons/fileupload/
。 

檔案上傳、表單項處理、效率問題基本上都考慮到了。在 Struts 中就使用了這個包,不過是用 Struts 的方式另行封裝了一次。這裡我們直接使用 fileupload 包。至於Struts 中的用法,請參閱 Struts 相關文檔。這個處理檔案上傳的 servelet 主要代碼如下: 

public void doPost( HttpServletRequest request, HttpServletResponse response ) 
{   
    DiskFileUpload diskFileUpload = new DiskFileUpload();    // 允許檔案最大長度 
    diskFileUpload.setSizeMax( 100*1024*1024 );    // 設定記憶體緩衝大小 
    diskFileUpload.setSizeThreshold( 4096 );    // 設定臨時目錄   
    diskFileUpload.setRepositoryPath( "c:/tmp" );  
    List fileItems = diskFileUpload.parseRequest( request );  
    Iterator iter = fileItems.iterator();    for( ; iter.hasNext(); ) 
    {    
    FileItem fileItem = (FileItem) iter.next();   
      if( fileItem.isFormField() ) {         // 當前是一個表單項    
    out.println( "form field : " + fileItem.getFieldName() + ", " + fileItem.getString() );    
      } else {       
    // 當前是一個上傳的檔案       
    String fileName = fileItem.getName();  
    fileItem.write( new File("c:/uploads/"+fileName) );     
      }  

}} 

為簡略起見,異常處理,檔案重新命名等細節沒有寫出。3、 用戶端發送內容構造假設接受檔案的網頁程式位於 http://192.168.29.65/upload_file/UploadFile.假設我們要發送一個二進位檔案、一個文字框表單項、一個密碼框表單項。檔案名稱為 E:\s ,其內容如下:(其中的XXX代表位元據,如 01 02 03)abbXXXccc 用戶端應該向 192.168.29.65 發送如下內容: 

POST /upload_file/UploadFile HTTP/1.1 
Accept: text/plain, */* 
Accept-Language: zh-cn 
Host: 192.168.29.65:80 
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6 
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org) 
Content-Length: 424 
Connection: Keep-Alive -----------------------------7d33a816d302b6 
Content-Disposition:form-data; 
name="userfile1"; 
filename="E:\s"Content-Type: 
application/octet-stream abbXXXccc 
-----------------------------7d33a816d302b6 

Content-Disposition: form-data; 

name="text1" foo 

-----------------------------7d33a816d302b6 

Content-Disposition: form-data; 

name="password1" bar 

-----------------------------7d33a816d302b6-- 

(上面有一個斷行符號)此內容必須一字不差,包括最後的斷行符號。 

注意:Content-Length: 424 這裡的424是紅色內容的總長度(包括最後的斷行符號) 
注意這一行:Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6 

根據 rfc1867, multipart/form-data是必須的.---------------------------7d33a816d302b6 是分隔字元,分隔多個檔案、表單項。 

其中33a816d302b6 是即時產生的一個數字,用以確保整個分隔字元不會在檔案或表單項的內容中出現。前面的 ---------------------------7d 是 IE 特有的標誌。 

Mozila 為---------------------------71用手工發送這個例子,在上述的 servlet 中檢驗通過。 

使用POST發送資料 

  以POST方式發送資料主要是為了向伺服器發送較大量的用戶端的資料,它不受URL的長度限制。POST請求將資料以URL編碼的形式放在HTTP本文中,欄位形式為fieldname=value,用&分隔每個欄位。注意所有的欄位都被作為字串處理。實際上我們要做的就是類比瀏覽器POST一個表單。以下是IE發送一個登陸表單的POST請求: 

POST http://127.0.0.1/login.do HTTP/1.0 
Accept: image/gif, image/jpeg, image/pjpeg, */* 
Accept-Language: en-us,zh-cn;q=0.5 
Content-Type: application/x-www-form-urlencoded 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) 
Content-Length: 28 
\r\n 
username=admin&password=1234 

  要在MIDP應用程式中類比瀏覽器發送這個POST請求,首先設定HttpConnection的請求方式為POST: 

hc.setRequestMethod(HttpConnection.POST); 

  然後構造出HTTP本文: 

byte[] data = "username=admin&password=1234".getBytes(); 

  並計算本文長度,填入Content-Type和Content-Length: 

hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
hc.setRequestProperty("Content-Length", String.valueOf(data.length)); 

  然後開啟OutputStream將本文寫入: 

OutputStream output = hc.openOutputStream(); 
output.write(data); 

  需要注意的是,資料仍需要以URL編碼格式編碼,由於MIDP庫中沒有J2SE中與之對應的URLEncoder類,因此,需要自己動手編寫這個encode()方法,可以參考java.net.URLEncoder.java的源碼。剩下的便是讀取伺服器響應,代碼與GET一致,這裡就不再詳述。 

  使用multipart/form-data傳送檔案 

  如果要在MIDP用戶端向伺服器上傳檔案,我們就必須類比一個POST multipart/form-data類型的請求,Content-Type必須是multipart/form-data。 

  以multipart/form-data編碼的POST請求格式與application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP要求標頭設定一個分隔字元,例如ABCD: 

hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD"); 

  然後,將每個欄位用“--分隔字元”分隔,最後一個“--分隔字元--”表示結束。例如,要上傳一個title欄位"Today"和一個檔案C:\1.txt,HTTP本文如下: 

--ABCD 
Content-Disposition: form-data; name="title" 
\r\n 
Today 
--ABCD 
Content-Disposition: form-data; name="1.txt"; filename="C:\1.txt" 
Content-Type: text/plain 
\r\n 
<這裡是1.txt檔案的內容> 
--ABCD-- 
\r\n 

  請注意,每一行都必須以\r\n結束,包括最後一行。如果用Sniffer程式檢測IE發送的POST請求,可以發現IE的分隔字元類似於---------------------------7d4a6d158c9,這是IE產生的一個隨機數,目的是防止上傳檔案中出現分隔字元導致伺服器無法正確識別檔案起始位置。我們可以寫一個固定的分隔字元,只要足夠複雜即可。 

  傳送檔案的POST代碼如下: 

String[] props = ... // 欄位名 
String[] values = ... // 欄位值 
byte[] file = ... // 檔案內容 
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔字元 
StringBuffer sb = new StringBuffer(); 
// 發送每個欄位: 
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"); 

// 傳送檔案: 
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(); 
// 設定HTTP頭: 
hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY); 
hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length + end_data.length)); 
// 輸出: 
output = hc.openOutputStream(); 
output.write(data); 
output.write(file); 
output.write(end_data); 
// 讀取伺服器響應: 
// TODO...

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.