1. 程式人生 > >瀏覽器原生 form 表單POST 數據的兩種方式

瀏覽器原生 form 表單POST 數據的兩種方式

mes 但是 lba lose -s ipa mvm 默認 字串

我們在提交表單的時候,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 數據的兩種方式