簡單寫個小例子,記錄一下此次大文件上傳遇到的所有問題。
一、客戶端(使用winform窗體實現)
具體功能:
-
- 點擊“選擇”按鈕,選擇要上傳的文件
- 點擊“上傳文件”按鈕,上傳該文件調用UpLoad_Request(string address, string fileNamePath, string saveName, ProgressBar progressBar)方法
- 在客戶端顯示上傳進度,已經時間,平均速度,上傳狀態,上傳大小
FileUpload 文件上傳類代碼:
public class FileUpload { /// <summary> /// 上傳文件 /// </summary> /// <param name="address">文件上傳到服務器的路徑</param> /// <param name="fileNamePath">要上傳的本地路徑(全路徑)</param> /// <param name="saveName">文件上傳后的名稱</param> /// <returns>成功返回1,失敗返回0</returns> public static int UpLoad_Request(string address, string fileNamePath, string saveName, ProgressBar progressBar) { int returnValue = 0; //要上傳的文件 FileStream fs = new FileStream(fileNamePath, FileMode.Open, FileAccess.Read); //二進制對象 BinaryReader r = new BinaryReader(fs); //時間戳 string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x"); byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "\r\n"); //請求的頭部信息 StringBuilder sb = new StringBuilder(); sb.Append("--"); sb.Append(strBoundary); sb.Append("\r\n"); sb.Append("Content-Disposition: form-data; name=\""); sb.Append("file"); sb.Append("\"; filename=\""); sb.Append(saveName); sb.Append("\";"); sb.Append("\r\n"); sb.Append("Content-Type: "); sb.Append("application/octet-stream"); sb.Append("\r\n"); sb.Append("\r\n"); string strPostHeader = sb.ToString(); byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader); // 根據uri創建HttpWebRequest對象 HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(address)); //對發送的數據不使用緩存 httpReq.AllowWriteStreamBuffering = false; //設置獲得響應的超時時間(3min) httpReq.Timeout = 180000; httpReq.KeepAlive = true; httpReq.ProtocolVersion = HttpVersion.Version11; httpReq.Method = "POST"; //對發送的數據不使用緩存 //httpReq.AllowWriteStreamBuffering = true; //設置獲得響應的超時時間(300s) //httpReq.Timeout = 300000; httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary; long length = fs.Length + postHeaderBytes.Length + boundaryBytes.Length; long fileLength = fs.Length; httpReq.ContentLength = length; try { progressBar.Maximum = int.MaxValue; progressBar.Minimum = 0; progressBar.Value = 0; //每次上傳8k int bufferLength = 8192; byte[] buffer = new byte[bufferLength]; //已上傳的字節數 long offset = 0; //開始上傳時間 DateTime startTime = DateTime.Now; int size = r.Read(buffer, 0, bufferLength); Stream postStream = httpReq.GetRequestStream(); //發送請求頭部消息 postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length); while (size > 0) { postStream.Write(buffer, 0, size); offset += size; progressBar.Value = (int)(offset * (int.MaxValue / length)); TimeSpan span = DateTime.Now - startTime; double second = span.TotalSeconds; Application.DoEvents(); size = r.Read(buffer, 0, bufferLength); } //添加尾部的時間戳 postStream.Write(boundaryBytes, 0, boundaryBytes.Length); postStream.Close(); //獲取服務器端的響應 WebResponse webRespon = httpReq.GetResponse(); Stream s = webRespon.GetResponseStream(); //讀取服務器端返回的消息 StreamReader sr = new StreamReader(s); String sReturnString = sr.ReadLine(); s.Close(); sr.Close(); if (sReturnString == "Success") { progressBar.Value = 100; returnValue = 1; } else if (sReturnString == "Error") { returnValue = 0; progressBar.Value = 0;//錯誤就得重新上傳,進度條置零 } } catch(Exception ex) { Console.WriteLine(ex.Message); returnValue = 0; } finally { fs.Close(); r.Close(); } return returnValue; } }
具體實現代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace UpFileClient { public partial class Form1 : Form { public Form1() { InitializeComponent(); } string filePath = ""; string FileName = ""; private void btnSelect_Click(object sender, EventArgs e) { //創建文件彈出選擇窗口(包括文件名)對象 OpenFileDialog ofd = new OpenFileDialog(); //判斷選擇的路徑 if (ofd.ShowDialog() == DialogResult.OK) { this.txtSoundPath.Text = ofd.FileName.ToString(); } filePath = this.txtSoundPath.Text; } private void btnUpLoad_Click(object sender, EventArgs e) { try { //上傳服務器的地址(web服務) string address = "http://localhost:61501/WebService/SaveFileWebForm.aspx"; //上傳后文件保存的名稱 string saveName = DateTime.Now.ToString("yyyyMMddHHmmss"); int count = FileUpload.UpLoad_Request(address, filePath, saveName, this.progressBar1); if (count > 0) { MessageBox.Show("上傳文件成功!"); } else { MessageBox.Show("上傳文件失敗!"); } }catch(Exception ex) { Console.WriteLine(ex.Message); } } } }
界面顯示
二、服務器端-提供文件上傳服務
1、創建一個web mvc項目,在創建一個webservice文件夾,在文件夾下創建一個SaveFileWebForm.axpx接口,
設置這個頁面為項目起始頁,打開這個頁面,右鍵查看代碼,編寫服務器端代碼,運行項目
項目結構:
客戶端上傳文件時,服務器端(SaveFileWebForm.axpx)需要訪問的到,(注:先運行服務器程序項目,在運行客戶端程序項目)
文件保存路徑和文件保存名可以根據實際需要設置
服務器端源碼:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace SaveFileWebService.WebService { public partial class SaveFileWebForm : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Request.Files.Count > 0) { try { //得到客戶端上傳的文件 HttpPostedFile file = Request.Files[0]; //服務器端要保存的路徑 string filePath = "D:\\Test\\" + file.FileName + ".mp3"; file.SaveAs(filePath); //返回結果 Response.Write("Success"); } catch { Response.Write("Error"); } } else { Response.Write("Error1"); } } } }
按照上面過程走下來,本來以為已經可以大功告成了,結果問題來了,小文件上傳沒問題,
超了4m的文件上傳不了,報錯引發的異常:“System.Net.WebException”(位於 System.dll 中)報400錯誤
在使用FileUpload控件時不少人遇到過上傳文件失敗的問題,其實是出於安全的原因,.Net運行時對請求文件最大長度作了限制,開發者需要手動修改下配置文件。
這是什么原因呢?我們仔細分析錯誤信息,說是“超過了最大請求長度”。
原來是有最大長度限制!那應該在哪里設置可以上傳更大的文件呢?
通過研究,可以修改web.config
增大可上傳文件的大小限制。同時還可以設置最大執行時間。代碼如下:
<httpRuntime maxRequestLength="204800" executionTimeout="600"/>
上述代碼maxRequestLength
的單位是KB,204800即是200MB。executionTimeout
的單位是秒。
通過上述設置,FileUpload就可以上傳超過4m大文件了。
你可能還不明白httpRuntime
的設置代碼該插入到web.config
哪個地方,如果放錯了,可能會導致web.config
配置文件失效,從而影響網站的正常運行。請參考文章《httpRuntime代碼放在web.config哪里?深度了解httpRuntime》。
修改web.config后上傳大於30M的文件失敗
通過上面介紹的方法,可以上傳超過4m的大文件了,但是當上傳大於30m的文件時,卻又提示失敗了!
這時好像httpRuntime
的maxRequestLength
設置已經無效了。這又是什么原因呢?
原來,IIS本身有請求長度限制!這時我們可以修改IIS配置來解決這個問題。
首先,打開IIS,如下圖
接下來,選擇自己的網站,停止,然后選中自己的站點,並雙擊“請求篩選”。
雙擊請求篩選之后,看到右邊操作中“編輯功能設置”,點擊“編輯功能設置”,打開界面
設置請求限制
在彈出的頁面中,我們看到默認請求限制正是30M,這時我們可以它改為更大的數字例如300M(300000000)以滿足自己的要求,根據自己的需求設置,我這里設置102400000
請注意,修改了IIS的“請求篩選”后,web.config
里同樣要設置httpRuntime
的maxRequestLength
的值大於30m。
到了這里是不是以為已經完成了呢,開心ing(*^▽^*)
不不不,其實還有
最后一個坑
添加system.webServer節點 修改服務器允許最大長度-requestLimits maxAllowedContentLength="1073741824"
<configuration> <system.webServer> <security> <requestFiltering> <!--修改服務器允許最大長度--> <requestLimits maxAllowedContentLength="1073741824"/> </requestFiltering> </security> </system.webServer> </configuration>
這個是我忘記設置的一個項,導致我浪費了一天時間,在糾結為何大文件上傳就是不行,該設置的已經設置了還是不行,都怪自己太粗心了,哎呀ε=(´ο`*)))
ok,到這里是真的完成了,整個過程很坎坷,一波三折,希望看到我這篇文章的朋友們,以后少走彎路哈~
有疑問有建議的歡迎留言指導~