原文連接:http://blog.csdn.net/five3/article/details/7181521
html
首先來了解什麼是multipart/form-data請求:app
根據http/1.1 rfc 2616的協議規定,咱們的請求方式只有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE等,那爲爲什麼咱們還會有multipart/form-data請求之說呢?這就要從頭來講了。tcp
http協議你們都知道是規定了以ASCII碼傳輸,創建在tcp、ip協議之上的應用層規範,規範內容把http請求分爲3個部門:狀態行,請求頭,請求體。全部的方法、實現都是圍繞如何運用和組織這三部分來完成的。換句話來講就是萬變不離其中,只要咱們瞭解了http請求的組成部分後,天然就能夠應變任何實際工做中的需求和問題了。工具
關於狀態行,請求頭,請求體等三部分的具體內容,你們能夠參考官方的協議文檔http://www.faqs.org/rfcs/rfc2616.html,這裏主要分析multipart/form-data請求具體是怎麼一回事。post
既然http協議自己的原始方法不支持multipart/form-data請求,那這個請求天然就是由這些原始的方法演變而來的,具體如何演變且看下文:spa
一、multipart/form-data的基礎方法是post,也就是說是由post方法來組合實現的.net
二、multipart/form-data與post方法的不一樣之處:請求頭,請求體。code
三、multipart/form-data的請求頭必須包含一個特殊的頭信息:Content-Type,且其值也必須規定爲multipart/form-data,同時還須要規定一個內容分割符用於分割請求體中的多個post的內容,如文件內容和文本內容天然須要分割開來,否則接收方就沒法正常解析和還原這個文件了。具體的頭信息以下:orm
//其中${bound} 是一個佔位符,表明咱們規定的分割符,能夠本身任意規定,但爲了不和正常文本重複了,儘可能要使用複雜一點的內容。如:--------------------56423498738365htm
四、multipart/form-data的請求體也是一個字符串,不過和post的請求體不一樣的是它的構造方式,post是簡單的name=value值鏈接,而multipart/form-data則是添加了分隔符等內容的構造體。具體格式以下:
其中${bound}爲以前頭信息中的分割符,若是頭信息中規定爲123,那麼這裏也要爲123,;能夠很容易看出,這個請求體是多個相同的部分組成的:每個部分都是以--加分隔符開始的,而後是該部份內容的描述信息,而後一個回車,而後是描述信息的具體內容;若是傳送的內容是一個文件的話,那麼還會包含文件名信息,以及文件內容的類型。上面的第二個小部分實際上是一個文件體的結構,最後會以--分割符--結尾,表示請求體結束。
綜上,能夠知道要發送一個multipart/form-data的請求,其實任何支持post請求的工具或語言均可以支持,只是本身要稍微包裝一下即可。
參考資料:
百度百科: http://baike.baidu.com/view/9472.htm
http1.1協議規範: http://www.faqs.org/rfcs/rfc2616.html
分析工具:httpAnalyzer
固然,附上C#源碼,應該很輕鬆就能夠轉Java
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Msf.Engine.Network.NetworkTool { public sealed class MultipartFormData : IDisposable { public const string Boundary = "--the_great_maoshu--"; public static string ContentType { get { return "multipart/form-data; boundary=" + Boundary; } } private MemoryStream _stream; public MemoryStream Stream { get { return _stream ?? (_stream = new MemoryStream()); } } public MultipartFormData() { } public void AddContent(string name, string value) { var sp = string.Format("--{0}\r\n", Boundary); sp += string.Format( "Content-Disposition: form-data; name=\"{0}\"; \r\n\r\n{1}", name, value); var data = Encoding.UTF8.GetBytes(sp); Stream.Write(data, 0, data.Length); } public void AddContent(string name, string fileName, byte[] fileData) { var sp = string.Format("--{0}\r\n", Boundary); sp += string.Format( "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", name, fileName); var data = Encoding.UTF8.GetBytes(sp); Stream.Write(data, 0, data.Length); Stream.Write(fileData, 0, fileData.Length); data = Encoding.UTF8.GetBytes("\r\n"); Stream.Write(data, 0, data.Length); } public byte[] GetPostData() { var sp = string.Format("--{0}--\r\n", Boundary); var data = Encoding.UTF8.GetBytes(sp); Stream.Write(data, 0, data.Length); Stream.Position = 0; return Stream.ToArray(); } public void Dispose() { if (_stream != null) _stream.Dispose(); _stream = null; } } }