.NET使⽤HttpClient以multipartform-data形式post上传⽂件。。
前⾔:
  本次要讲的是使⽤.Net HttpClient拼接multipark/form-data形式post上传⽂件和相关参数,并接收到上传⽂件成功后返回过来的结果(图⽚地址,和是否成功)。可能有很多⼈会说⽤ajax不是就可以轻松的实现吗?的确是在不存在跨域问题的前提下使⽤ajax上传⽂件,接收返回结果是最佳的选择。⽆奈的是我们对接的是第三⽅的⼀个上传图⽚的接⼝,⽽且对⽅并没有对我们的域名设置允许跨域,为了能够解决这⼀问题我们只能够通过后端请求避免跨域问题。
什么是multipart/form-data请求:
关于multipart/form-data详情查看:
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);
s = 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"
};
inputtypefile不上传文件list.Add(dataContent3);
var dataContent4 = new ByteArrayContent(Encoding.UTF8.GetBytes(sign));
dataContent4.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "sign"
};
list.Add(dataContent4);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("xxxxxx/imageUpload/", content).Result;//post请求
return result.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}
使⽤Fiddler 4 抓包查看请求的参数:
因为我们没有办法看到我们所拼接成功后的multipark/form-data形式的数据,想要看到对应拼接的请求参数可以使⽤ Fiddler 4 抓包⼯具查看:关于Fiddler 4抓包⼯具的使⽤可以阅读该篇博客:
抓包获取到的multipark/form-data形式的请求参数如下图:
总结:
  写到最后才发现,原本只需要⼀个简单的请求就可以解决的问题因为跨域把这个问题变得如此繁琐,搞得真叫⼈蛋痛。这⾥我试过了很多种⽅式拼接multipark/form-data形式的请求参数,最后在坚持不懈的尝试下终于成功了。