普通的類比提交表單的操作只要構建html協議中的資料就行,但是表單中如果含有file的話, 也就是說含有附件上傳的內容的話怎樣提交呢?
使用multipart/form-data傳送檔案
如果要在用戶端向伺服器上傳檔案,我們就必須類比一個POST multipart/form-data類型的請求,Content-Type必須是multipart/form-data。
以multipart/form-data編碼的POST請求格式與application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP要求標頭設定一個分隔字元,例如ABCD:
我們類比的提交要設定 content-type不同於非含附件的post時候的content-type,這裡需要: ("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產生的一個隨機數,目的是防止上傳檔案中出現分隔字元導致伺服器無法正確識別檔案起始位置。我們可以寫一個固定的分隔字元,只要足夠複雜即可。
下面是一段java的post 帶附件的類比發送程式段:
傳送檔案的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...