應用程序中上傳附件是最常使用的操做之一,ASP.NET客戶端通常經過上傳控件實現,html
<input type="file" id="fileUpload" runat="server" />
後臺C#使用如下方式將文件保存到服務上web
1 HttpFileCollection files = HttpContext.Current.Request.Files; 2 HttpPostedFile postedFile = files["fileUpload"]; 3 postedFile.SaveAs(postedFile.FileName);
上述的場景是簡單的管理系統與網站中最經常使用的方式將客戶端的文件上傳到IIS服務器的指定目錄下。數組
隨着雲端應用的發展與普及,第三方應用平臺或者開發平臺部署在雲服務器上,例如阿里雲、騰訊雲、七牛雲、青雲等。第三方對外開放的應用平臺大都是提供Restful API供開發者調用以上傳(本地或者遠端文件)或下載業務數據進行業務開發。服務器
傳統應用程序的上傳控件方式在雲端應用程序中針對附件上傳與下載徹底不適用。網絡
下面提供一種通用的上傳附件的方式:app
1 /// <summary> 2 /// 將數據緩衝區(通常是指文件流或內存流對應的字節數組)上載到由 URI 標識的資源。(包含body數據) 3 /// </summary> 4 /// <param name="url">請求目標URL</param> 5 /// <param name="data">主體數據(字節數據)</param> 6 /// <param name="method">請求的方法。請使用 WebRequestMethods.Http 的枚舉值</param> 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 標頭的值。請使用 ContentType 類的常量來獲取。默認爲 application/octet-stream</param> 8 /// <returns>HTTP-POST的響應結果</returns> 9 public HttpResult UploadData(string url, byte[] data, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM) 10 { 11 HttpResult httpResult = new HttpResult(); 12 HttpWebRequest httpWebRequest = null; 13 14 try 15 { 16 httpWebRequest = WebRequest.Create(url) as HttpWebRequest; 17 httpWebRequest.Method = method; 18 httpWebRequest.Headers = HeaderCollection; 19 httpWebRequest.CookieContainer = CookieContainer; 20 httpWebRequest.ContentLength = data.Length; 21 httpWebRequest.ContentType = contentType; 22 httpWebRequest.UserAgent = _userAgent; 23 httpWebRequest.AllowAutoRedirect = _allowAutoRedirect; 24 httpWebRequest.ServicePoint.Expect100Continue = false; 25 26 if (data != null) 27 { 28 httpWebRequest.AllowWriteStreamBuffering = true; 29 using (Stream requestStream = httpWebRequest.GetRequestStream()) 30 { 31 requestStream.Write(data, 0, data.Length); 32 requestStream.Flush(); 33 } 34 } 35 36 HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse; 37 if (httpWebResponse != null) 38 { 39 GetResponse(ref httpResult, httpWebResponse); 40 httpWebResponse.Close(); 41 } 42 } 43 catch (WebException webException) 44 { 45 GetWebExceptionResponse(ref httpResult, webException); 46 } 47 catch (Exception ex) 48 { 49 GetExceptionResponse(ref httpResult, ex, method, contentType); 50 } 51 finally 52 { 53 if (httpWebRequest != null) 54 { 55 httpWebRequest.Abort(); 56 } 57 } 58 59 return httpResult; 60 }
藉助該方法,又衍生出一下2中重載方式:函數
重載1:將指定的本地文件上載到具備指定的 URI 的資源。(包含body數據)post
1 /// <summary> 2 /// 將指定的本地文件上載到具備指定的 URI 的資源。(包含body數據) 3 /// </summary> 4 /// <param name="url">請求目標URL</param> 5 /// <param name="fileFullName">待上傳的文件(包含全路徑的徹底限定名)</param> 6 /// <param name="method">請求的方法。請使用 WebRequestMethods.Http 的枚舉值</param> 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 標頭的值。請使用 ContentType 類的常量來獲取。默認爲 application/octet-stream</param> 8 /// <returns>HTTP-POST的響應結果</returns> 9 public HttpResult UploadFile(string url, string fileFullName, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM) 10 { 11 HttpResult httpResult = new HttpResult(); 12 if (!File.Exists(fileFullName)) 13 { 14 httpResult.Status = HttpResult.STATUS_FAIL; 15 16 httpResult.RefCode = (int)HttpStatusCode2.USER_FILE_NOT_EXISTS; 17 httpResult.RefText = HttpStatusCode2.USER_FILE_NOT_EXISTS.GetCustomAttributeDescription(); 18 } 19 else 20 { 21 FileStream fileStream = new FileStream(fileFullName, FileMode.Open, FileAccess.Read); 22 byte[] data = fileStream.ToByteArray(); 23 httpResult = UploadData(url, data, method, contentType); 24 } 25 26 return httpResult; 27 }
重載2: 將指定的數據流對象(通常指文件流或內存流)上載到具備指定的 URI 的資源。(包含body數據)網站
1 /// <summary> 2 /// 將指定的數據流對象(通常指文件流或內存流)上載到具備指定的 URI 的資源。(包含body數據) 3 /// </summary> 4 /// <param name="url">請求目標URL</param> 5 /// <param name="stream">通常指文件流或內存流</param> 6 /// <param name="method">請求的方法。請使用 WebRequestMethods.Http 的枚舉值</param> 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 標頭的值。請使用 ContentType 類的常量來獲取。默認爲 application/octet-stream</param> 8 /// <returns>HTTP-POST的響應結果</returns> 9 public HttpResult UploadStream(string url, Stream stream, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM) 10 { 11 HttpResult httpResult = new HttpResult(); 12 if (stream == null) 13 { 14 httpResult.Status = HttpResult.STATUS_FAIL; 15 16 httpResult.RefCode = (int)HttpStatusCode2.USER_STREAM_NULL; 17 httpResult.RefText = HttpStatusCode2.USER_STREAM_NULL.GetCustomAttributeDescription(); 18 } 19 else 20 { 21 byte[] data = stream.ToByteArray(); 22 httpResult = UploadData(url, data, method, contentType); 23 } 24 25 return httpResult; 26 }
其中 UploadData() 調用了 GetResponse()、GetWebExceptionResponse()、GetExceptionResponse()方法ui
1 /// <summary> 2 /// 獲取HTTP的響應信息 3 /// </summary> 4 /// <param name="httpResult">即將被HTTP請求封裝函數返回的HttpResult變量</param> 5 /// <param name="httpWebResponse">正在被讀取的HTTP響應</param> 6 private void GetResponse(ref HttpResult httpResult, HttpWebResponse httpWebResponse) 7 { 8 httpResult.HttpWebResponse = httpWebResponse; 9 httpResult.Status = HttpResult.STATUS_SUCCESS; 10 httpResult.StatusDescription = httpWebResponse.StatusDescription; 11 httpResult.StatusCode = (int)httpWebResponse.StatusCode; 12 13 if (ReadMode == ResponseReadMode.Binary) 14 { 15 int len = (int)httpWebResponse.ContentLength; 16 httpResult.Data = new byte[len]; 17 int bytesLeft = len; 18 int bytesRead = 0; 19 20 using (BinaryReader br = new BinaryReader(httpWebResponse.GetResponseStream())) 21 { 22 while (bytesLeft > 0) 23 { 24 bytesRead = br.Read(httpResult.Data, len - bytesLeft, bytesLeft); 25 bytesLeft -= bytesRead; 26 } 27 } 28 } 29 else 30 { 31 using (StreamReader sr = new StreamReader(httpWebResponse.GetResponseStream())) 32 { 33 httpResult.Text = sr.ReadToEnd(); 34 } 35 } 36 }
1 /// <summary> 2 /// 獲取HTTP訪問網絡期間發生錯誤時引起的異常響應信息 3 /// </summary> 4 /// <param name="httpResult">即將被HTTP請求封裝函數返回的HttpResult變量</param> 5 /// <param name="webException">訪問網絡期間發生錯誤時引起的異常對象</param> 6 private void GetWebExceptionResponse(ref HttpResult httpResult, WebException webException) 7 { 8 HttpWebResponse exResponse = webException.Response as HttpWebResponse; 9 if (exResponse != null) 10 { 11 httpResult.HttpWebResponse = exResponse; 12 httpResult.Status = HttpResult.STATUS_FAIL; 13 httpResult.StatusDescription = exResponse.StatusDescription; 14 httpResult.StatusCode = (int)exResponse.StatusCode; 15 16 httpResult.RefCode = httpResult.StatusCode; 17 using (StreamReader sr = new StreamReader(exResponse.GetResponseStream(), EncodingType)) 18 { 19 httpResult.Text = sr.ReadToEnd(); 20 httpResult.RefText = httpResult.Text; 21 } 22 23 exResponse.Close(); 24 } 25 }
/// <summary> /// 獲取HTTP的異常響應信息 /// </summary> /// <param name="httpResult">即將被HTTP請求封裝函數返回的HttpResult變量</param> /// <param name="ex">異常對象</param> /// <param name="method">HTTP請求的方式</param> /// <param name="contentType">HTTP的標頭類型</param> private void GetExceptionResponse(ref HttpResult httpResult, Exception ex, string method, string contentType = "") { contentType = string.IsNullOrWhiteSpace(contentType) ? string.Empty : "-" + contentType; StringBuilder sb = new StringBuilder(); sb.AppendFormat("[{0}] [{1}] [HTTP-" + method + contentType + "] Error: ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), _userAgent); Exception exception = ex; while (exception != null) { sb.AppendLine(exception.Message + " "); exception = exception.InnerException; } sb.AppendLine(); httpResult.HttpWebResponse = null; httpResult.Status = HttpResult.STATUS_FAIL; httpResult.RefCode = (int)HttpStatusCode2.USER_UNDEF; httpResult.RefText += sb.ToString(); }