.NET使用HttpClient以multipart/form-data形式post上傳文件及其相關參數

  • 2019 年 10 月 3 日
  • 筆記

前言:

  本次要講的是使用.Net HttpClient拼接multipark/form-data形式post上傳文件和相關參數,並接收到上傳文件成功後返回過來的結果(圖片地址,和是否成功)。可能有很多人會說用ajax不是就可以輕鬆的實現嗎?的確是在不存在跨域問題的前提下使用ajax上傳文件,接收返回結果是最佳的選擇。無奈的是我們對接的是第三方的一個上傳圖片的介面,而且對方並沒有對我們的域名設置允許跨域,為了能夠解決這一問題我們只能夠通過後端請求避免跨域問題。

什麼是multipart/form-data請求:

關於multipart/form-data詳情查看: https://www.cnblogs.com/tylerdonet/p/5722858.html

Html上傳圖片按鈕:

<div class="cover-hd">  <a href="javascript:;" class="a-uploadCustom">  <input type="file" id="Logoimg" onchange="OnchangeImage(this)" /></a>  </div>

使用ajax將圖片文件流和相關參數傳遞到後端進行拼接:

注意:因為我這裡調用第三方介面需要傳遞(appid應用程式唯一標識,random隨機數,和sign簽名)

<script type="text/javascript">      //後端圖片上傳      function OnchangeImage(obj) {          var formData = new FormData();          var files = $(obj).prop('files'); //獲取到文件列表          console.log(files[0]);          formData.append("imgType", 1);          formData.append("appId","你需要傳遞的參數");          formData.append("random", "你需要傳遞的參數");          formData.append("file", files[0]);//圖片文件流          formData.append("sign", "你需要傳遞的參數");            console.log(formData);          jQuery.support.cors = true;          $.ajax({              async: true,              contentType: false, //頭部請求內容格式              dataType: 'json',              type: 'post',              data:formData,              // 告訴jQuery不要去處理髮送的數據              processData: false,              url: "@Url.Action("ImageUpload", "MtVirtualStore")",//後端接收圖片介面              success: function(data) {                  //後端Httpclient請求成功後返回過來的結果                  console.log(data);              }          });      }  </script>

 

後端接收圖片和參數,並將圖片文件流轉化為圖片位元組類型數據:

//接收前端圖片文件資訊  [HttpPost]  public JsonResult ImageUpload(FormContext context)  {  HttpPostedFileBase fileData = Request.Files[0];  string appId=Request["appId"];  string random=Request["random"];  string sign=Request["sign"];  string imgType=Request["imgType"];  if (fileData != null)  {  try{  string fileName = Path.GetFileName(fileData.FileName);//原始文件名稱  byte[] byteFileData = ReadFileBytes(fileData);//文件流轉為位元組流    var resultContext =HttpClientPostUpload(byteFileData,appId,random,sign,imgType, fileName);    return Json(new { code = 1, list = resultContext,msg="上傳成功~"});  }  catch (Exception ex)  {  return Json(new { code = 0, msg = ex.Message });  }  }  else  {  return Json(new { code = 0, msg = "圖片上傳失敗,請稍後再試~" });  }  }    //文件流轉化為位元組  /// <summary>  /// 文件流類型轉化位元組類型  /// </summary>  /// <param name="fileData">文件流數據</param>  /// <returns></returns>  private byte[] ReadFileBytes(HttpPostedFileBase fileData)  {  byte[] data;  using (Stream inputStream = fileData.InputStream)  {  MemoryStream memoryStream = inputStream as MemoryStream;  if (memoryStream == null)  {  memoryStream = new MemoryStream();  inputStream.CopyTo(memoryStream);  }  data = memoryStream.ToArray();  }  return data;  }

重點,HttpClient拼接multipart/form-data形式參數post提交數據:

/// <summary>  /// 向目標地址提交圖片文件參數數據  /// </summary>  /// <param name="bmpBytes">圖片位元組流</param>  /// <param name="appId">appid</param>  /// <param name="random">隨機數</param>  /// <param name="sign">簽名</param>  /// <param name="imgType">上傳圖片類型</param>  /// <param name="fileName">圖片名稱</param>  /// <returns></returns>  public string HttpClientPostUpload(byte [] bmpBytes, string appId, string random,,string sign,string imgType,string fileName)  {  using (var client = new HttpClient())  {  List<ByteArrayContent> list = new List<ByteArrayContent>();    var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(appId));  dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")//內容處置標頭  {  Name = "appId"  };  list.Add(dataContent);    var dataContent2 = new ByteArrayContent(Encoding.UTF8.GetBytes(imgType));  dataContent2.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")  {  Name = "imgType"  };  list.Add(dataContent2);    var dataContent3 = new ByteArrayContent(Encoding.UTF8.GetBytes(random));  dataContent3.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")  {  Name = "random"  };  list.Add(dataContent3);    var dataContent4 = new ByteArrayContent(Encoding.UTF8.GetBytes(sign));  dataContent4.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")  {  Name = "sign"  };  list.Add(dataContent4);  List<ByteArrayContent> list2 = new List<ByteArrayContent>();    var fileContent = new ByteArrayContent(bmpBytes);//填充圖片位元組  fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")  {  Name="file",  FileName=fileName  };  list.Add(fileContent);    using (var content =new MultipartFormDataContent())  {  Action<List<ByteArrayContent>> act = (dataContents) =>  {//聲明一個委託,該委託的作用就是將ByteArrayContent集合加入到MultipartFormDataContent中  foreach (var byteArrayContent in dataContents)  {  content.Add(byteArrayContent);  }  };    act(list);//執行act  try  {  var result = client.PostAsync("https://xxxxxx.com/imageUpload/", content).Result;//post請求  return result.Content.ReadAsStringAsync().Result;  }  catch (Exception ex)  {  return ex.Message;  }    }  }  }

使用Fiddler 4 抓包查看請求的參數:

因為我們沒有辦法看到我們所拼接成功後的multipark/form-data形式的數據,想要看到對應拼接的請求參數可以使用 Fiddler 4 抓包工具查看:

關於Fiddler 4抓包工具的使用可以閱讀該篇部落格:https://www.jianshu.com/p/55f7be58a7e4

抓包獲取到的multipark/form-data形式的請求參數如下圖:

總結:

  寫到最後才發現,原本只需要一個簡單的請求就可以解決的問題因為跨域把這個問題變得如此繁瑣,搞得真叫人蛋痛。這裡我試過了很多種方式拼接multipark/form-data形式的請求參數,最後在堅持不懈的嘗試下終於成功了。