瀏覽器原生 form 表單POST 數據的兩種方式
我們在提交表單的時候,form表單參數中會有一個enctype的參數。enctype指定了HTTP請求的Content-Type。
常用有兩種:application/x-www-form-urlencoded和multipart/form-data。
application/x-www-form-urlencoded: 窗體數據被編碼為名稱/值對,並且將提交的數據進行urlencode。默認情況下,我們所有的表單提交都是通過這種默認的方式實現的。
multipart/form-data: 窗體數據被編碼為一條消息,頁上的每個控件對應消息中的一個部分。
當action為get時候,瀏覽器用x-www-form-urlencoded的編碼方式把form數據轉換成一個字串(name1=value1&name2=value2...),然後把這個字串append到url後面,用?分割,加載這個新的url。
當action為post時候,瀏覽器把form數據封裝到http body中,然後發送到server。 如果沒有type=file的控件,用默認的application/x-www-form-urlencoded就可以了。
請求標頭:
請求正文:
loginType=1&loginName=operator&pwd=%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0&verifyCode=6987
首先,Content-Type 被指定為 application/x-www-form-urlencoded;其次,提交的數據按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。大部分服務端語言都對這種方式有很好的支持。
但是如果有type=file的話,就要用到multipart/form-data了。瀏覽器會把整個表單以控件為單位分割,並為每個部分加上Content-Disposition(form-data或者file),Content-Type(默認為text/plain),name(控件name)等信息,並加上分割符(boundary)。
Multipart/form-data其實就是瀏覽器用表單上傳文件的方式。最常見的情境是:在寫郵件時,向郵件後添加附件,附件通常使用表單添加,也就是用multipart/form-data格式上傳到服務器。
具體的步驟是怎樣的呢?
首先,客戶端和服務器建立連接(TCP
第二,客戶端可以向服務器端發送數據。因為上傳文件實質上也是向服務器端發送請求。
第三,客戶端按照符合“multipart/form-data”的格式向服務器端發送數據。
服務端接收的http請求標頭:
請求正文:
-----------------------------7e11a616672236 Content-Disposition: form-data; name="id" 17e832d6a79744eaae6d79237e82e3a4 -----------------------------7e11a616672236 Content-Disposition: form-data; name="templateType" 1 -----------------------------7e11a616672236 Content-Disposition: form-data; name="file"; filename="" Content-Type: application/octet-stream <二進制文件數據未顯示> ---------------------------7e11a616672236 Content-Disposition: form-data; name="imagesTemplate" -----------------------------7e11a616672236 Content-Disposition: form-data; name="attachTemplate" -----------------------------7e11a616672236 Content-Disposition: form-data; name="ajax" 1 -----------------------------7e11a616672236--
這行指出這個請求是“multipart/form-data”格式的,且“boundary”是 “---------------------------7e11a616672236”這個字符串。
不難想象,“boundary”是用來隔開表單中不同部分數據的。例子中的表單就有 6 部分數據,用“boundary”隔開。“boundary”一般由系統隨機產生,但也可以簡單的用“-------------”來代替。
實際上,每部分數據的開頭都是由"--" + boundary開始,而不是由 boundary 開始。仔細看才能發現下面的開頭這段字符串實際上要比 boundary 多了個 “--”
緊接著 boundary 的是該部分數據的描述。
在請求的最後,則是 "--" + boundary + "--" 表明表單的結束。
需要註意的是,在html協議中,用 “/r/n” 換行,而不是 “/n”。
附C#組裝代碼:
var memStream = new MemoryStream(); //https支持 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(httpUrl); // 邊界符 var boundary = "---------------" + DateTime.Now.Ticks.ToString("x"); // 邊界符 var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n"); // 最後的結束符 var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n"); memStream.Write(beginBoundary, 0, beginBoundary.Length); // 設置屬性 request.Method = "POST"; request.Timeout = 50000000; request.ReadWriteTimeout = 30000000; request.ContentType = "multipart/form-data; boundary=" + boundary; var stringKeyHeader = "Content-Disposition: form-data; name=\"{0}\"" + "\r\n\r\n{1}\r\n"; var header = string.Format(stringKeyHeader, "REQMESSAGE", bodyJson); var headerbytes = Encoding.UTF8.GetBytes(header); memStream.Write(headerbytes, 0, headerbytes.Length); memStream.Write(beginBoundary, 0, beginBoundary.Length); header = string.Format(stringKeyHeader, "AUTHMESSAGE", authJson); headerbytes = Encoding.UTF8.GetBytes(header); memStream.Write(headerbytes, 0, headerbytes.Length); memStream.Write(endBoundary, 0, endBoundary.Length); request.ContentLength = memStream.Length; Stream requestStream = request.GetRequestStream(); memStream.Position = 0; var tempBuffer = new byte[memStream.Length]; memStream.Read(tempBuffer, 0, tempBuffer.Length); memStream.Close(); requestStream.Write(tempBuffer, 0, tempBuffer.Length); requestStream.Close(); /*string s = System.Text.Encoding.UTF8.GetString(tempBuffer, 0, tempBuffer.Length); Console.WriteLine(s);*/ HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8"));//("gb2312")); resultInfo = sr.ReadToEnd();
實現的是傳遞兩個json串
瀏覽器原生 form 表單POST 數據的兩種方式