這一陣子因為項目需要要對接別家公司的restful接口,其中有一個接口是上傳視頻文件。接着上網找找資料。后來文件是上傳成功了,但上服務器一看,文件沒有后綴,我勒個去,這是什么個鬼。接着繼續找資料,最終發現是因為在文件數據后面沒加上“\r\n”引起的,特發此博文備忘。在此感謝【小伊同學】的《c#代碼發送post請求,上傳文件》https://www.cnblogs.com/yinq/p/6045995.html和【imEgo】的《HTTP POST上傳文件格式說明》http://blog.sina.com.cn/s/blog_73b633110101jwxm.html。
1 public static Response FileLoadRequest(string url, string filePath, string rename = "") 2 { 3 Response httpResponse = null; 4 string fileName = FileHelper.GetFileName(filePath); 5 string boundary = "ceshi"; 6 string Enter = "\r\n"; 7 8 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 9 request.Method = "POST"; 10 request.ContentType = "multipart/form-data;charset=utf8;boundary=" + boundary; //boundary這個屬性很重要 11 //進行Session持久化 12 request.CookieContainer = cookie; 13 14 #region 將參數寫入請求流中 15 Stream RequestStream = request.GetRequestStream(); 16 string fileContentStr = "--" + boundary + Enter 17 + "Content-Type:application/octet-stream" + Enter 18 + "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"" + Enter + Enter; 19 var fileContentStrByte = Encoding.UTF8.GetBytes(fileContentStr); 20 21 FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); 22 byte[] filedata = new byte[fs.Length]; 23 fs.Read(filedata, 0, Convert.ToInt32(fs.Length)); 24 fs.Close(); 25 26 RequestStream.Write(fileContentStrByte, 0, fileContentStrByte.Length); 27 RequestStream.Write(filedata, 0, filedata.Length); 28 29 //在文件數據末尾要加上“\r\n” 30 string EndStr1 = Enter; 31 var EndStr1Byte = Encoding.UTF8.GetBytes(EndStr1); 32 RequestStream.Write(EndStr1Byte, 0, EndStr1Byte.Length); 33 34 if (rename != "") 35 { 36 string fileNameStr = "--" + boundary + Enter 37 + "Content-Disposition: form-data; name=\"file_name\"" + Enter + Enter 38 + rename; 39 var fileNameStrByte = Encoding.UTF8.GetBytes(fileNameStr); 40 RequestStream.Write(fileNameStrByte, 0, fileNameStrByte.Length); 41 } 42 43 //在流末尾要加上--ceshi--的分隔符 44 string EndStr = Enter + "--" + boundary + "--"; 45 var EndStrByte = Encoding.UTF8.GetBytes(EndStr); 46 RequestStream.Write(EndStrByte, 0, EndStrByte.Length); 47 #endregion 48 49 string responseMessage = string.Empty; 50 try 51 { 52 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 53 { 54 55 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); 56 responseMessage = sr.ReadToEnd(); 57 httpResponse = JsonConvert.DeserializeObject<Response>(responseMessage); 58 response.Close(); 59 } 60 } 61 catch (WebException ex) 62 { 63 Program.log.Error(string.Format("System.Net.WebException:UrlGetRequest出錯,URL='{0}':", request.RequestUri), ex); 64 } 65 catch (Exception ex) 66 { 67 Program.log.Error(string.Format("UrlGetRequest出錯,URL='{0}':", request.RequestUri), ex); 68 } 69 70 return httpResponse; 71 }
下面引用下RFC的Sample:
Content-Type: multipart/form-data, boundary=AaB03x --AaB03x Content-Disposition: form-data; name="field1" Joe Blow --AaB03x Content-Disposition: form-data; name="pics"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x--
首先,在Content-Type中,boundary這個屬性一定要加,但boundary屬性值隨意設置成什么都行,它不會出現在要上傳的數據里,只是起到分隔的作用。上面是設置成“Aab03x”。重點來了:每個參數之前需要加上“--boundary”,注意前面有“--”。參數最后結尾要加“--boundary--”。文件數據后要跟上“\r\n”(我就是因為沒加“\r\n,所以沒有文件后綴”)。在上傳文件的那一個參數的Content-Type:是根據上傳文件的后綴進行設置的,詳細對照表請參照:http://tool.oschina.net/commons/。如果不想根據文件后綴進行填充的話,可以直接用“application/octet-stream”。