- 當form標簽的enctype設置為multipart/form-data瀏覽器都干了些什么呢?
通常我們在做向服務器提交數據的功能時都會用到表單提交,默認情況下表單的enctype屬性值為application/x-www-form-urlencoded,在想服務器發送數據前,所有的字符都會進行編碼(空格轉換為“+”號,特殊符號轉換為ASCII HEX值,如“<”會轉換為“%3C”);但是當我們想要做一個的包含上傳的數據提交功能時,就必須要將form標簽的enctype屬性設置為multipart/form-data才可以,那么此時瀏覽器都干了些什么,接下來我們抓取一下提交表單時的請求,如下圖所示:
在請求頭中我們發現Content-Type后面的值中有boundary的鍵后面跟着一串“不明所以”的字符,在Requset PayLoad中每一個Content-Disposition前面都有同樣的字符,boundary的翻譯成中文就是分界線的意思,現在意思已經很明顯了吧,就是說這段“不明所以”的字符串是用來分割表單中的每個數據項的,以圖中最后一個紅色圈選的字符串代表本次數據表單的結尾,當服務器接受到這樣的格式的請求主體信息后 ,會根據Content-Type中的boundary的值來解析對應的數據。
2.通過代碼來實現form以multipart/form-data的方式來提交數據
編寫代碼過程中需要注意一下幾點:
- 每行字符串結束后都需要以“\r\n”換新行,特別注意一下在文件流寫入到請求主體后也要有“\r\n”換行;
- boundary的值不能和表單數據沖突;
- Content-Type后面的boundary值的前綴長度不能和Request PayLoad中的boundary前綴長度一樣
代碼如下:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:24219/upload.ashx"); //邊界標識 string boundary = "WebKitFormBoundary" + Guid.NewGuid().ToString("N"); //開始邊界 string beginBoundary = "------" + boundary; //結束邊界 string endBoundary = "------" + boundary + "--"; request.ContentType = "multipart/form-data; boundary=----" + boundary; request.Method = "POST"; Stream requestStream = request.GetRequestStream(); //鍵值對 StringBuilder keyValueParam = new StringBuilder(); keyValueParam.AppendLine(beginBoundary); keyValueParam.AppendLine("Content-Disposition: form-data; name=\"name\""); keyValueParam.AppendLine(); keyValueParam.AppendLine("o_1bfj088gv38436s13777eo1dtn1o.jpg"); keyValueParam.AppendLine(beginBoundary); keyValueParam.AppendLine("Content-Disposition: form-data; name=\"chunks\""); keyValueParam.AppendLine(); keyValueParam.AppendLine("5"); byte[] keyValueByte = Encoding.UTF8.GetBytes(keyValueParam.ToString()); requestStream.Write(keyValueByte, 0, keyValueByte.Length); //文件 StringBuilder fileParam = new StringBuilder(); fileParam.AppendLine(beginBoundary); fileParam.AppendLine("Content-Disposition: form-data; name=\"file\"; filename=\"370x323-3.jpg\""); fileParam.AppendLine("Content-Type: application/octet-stream"); fileParam.AppendLine(); byte[] fileParamBytes = Encoding.UTF8.GetBytes(fileParam.ToString()); requestStream.Write(fileParamBytes, 0, fileParamBytes.Length); byte[] fileByte = File.ReadAllBytes(@"C:\Users\CSQ\Desktop\新建文件夾\370x323-2.jpg"); requestStream.Write(fileByte, 0, fileByte.Length); //結束邊界 StringBuilder endParam = new StringBuilder(); endParam.AppendLine(); endParam.AppendLine(endBoundary);//結束邊界 byte[] endByte = Encoding.UTF8.GetBytes(endParam.ToString()); requestStream.Write(endByte, 0, endByte.Length); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader reader = new StreamReader(responseStream); string result = reader.ReadToEnd();
這是用HttpWebRequest來編寫的,換做HttpClient類來編寫的話就更簡單了,哈哈,看代碼:
HttpClient client = new HttpClient(); //multipart/form-data類型的請求內容 MultipartFormDataContent httpContents = new MultipartFormDataContent(); byte[] fileByte = File.ReadAllBytes(@"C:\Users\Alan\Desktop\新建文件夾\370x323-2.jpg"); ByteArrayContent fileContent = new ByteArrayContent(fileByte); fileContent.Headers.ContentType =new MediaTypeHeaderValue("application/octet-stream"); httpContents.Add(fileContent, "file", "370x323-2.jpg"); ByteArrayContent keyValue1 = new ByteArrayContent(Encoding.UTF8.GetBytes("o_1bfj088gv38436s13777eo1dtn1o.jpg")); httpContents.Add(keyValue1, "name"); ByteArrayContent keyValue2 = new ByteArrayContent(Encoding.UTF8.GetBytes("5")); httpContents.Add(keyValue2, "chunks"); var response = client.PostAsync("http://localhost:24219/upload.ashx", httpContents).Result; response.EnsureSuccessStatusCode();
是不是很容易啊,完結!