C# HTTP系列11 以普通文件流方式上傳文件遠程伺服器

  • 2019 年 10 月 5 日
  • 筆記

系列目錄 【已更新最新開發文章,點擊查看詳細】

應用程式中上傳附件是最常使用的操作之一,ASP.NET客戶端一般通過上傳控制項實現,

<input type="file" id="fileUpload" runat="server" />

後台C#使用以下方式將文件保存到服務上

1 HttpFileCollection files = HttpContext.Current.Request.Files;  2 HttpPostedFile postedFile = files["fileUpload"];  3 postedFile.SaveAs(postedFile.FileName);

上述的場景是簡單的管理系統與網站中最常用的方式將客戶端的文件上傳到IIS伺服器的指定目錄下。

隨著雲端應用的發展與普及,第三方應用平台或者開發平台部署在雲伺服器上,例如阿里雲、騰訊雲、七牛雲、青雲等。第三方對外開放的應用平台大都是提供Restful API供開發者調用以上傳(本地或者遠端文件)或下載業務數據進行業務開發。

傳統應用程式的上傳控制項方式在雲端應用程式中針對附件上傳與下載完全不適用。

下面提供一種通用的上傳附件的方式:

 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數據)

 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()方法

 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();  }

系列目錄 【已更新最新開發文章,點擊查看詳細】