.NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)
需求背景:
在需要通过服务端请求传递文件二进制文件流数据到相关的服务端保存时,如对接第三方接口很多情况下都会提供一个上传文件的接口,但是当你直接通过前端Ajax的方式将文件流上传到对方提供的接口的时候往往都会存在跨域的情况,这时候我们就需要通过服务端提交文件流来解决这个跨域的情况。本篇的主角就是使用HttpClient进行Http请求,提交二进制文件流到文件服务器中。
HttpClient简单介绍:
HttpClient类实例充当发送 HTTP 请求的会话。 HttpClient实例是对该实例执行的所有请求应用的设置的集合。 此外,每个 HttpClient 实例都使用其自己的连接池,并从其他实例所执行的请求隔离其请求 HttpClient 。
使用注意点:HttpClient对象比较特殊,虽然继承了IDisposable这个接口但是它可以被共享实例,并且使用完不能立即关闭连接、性能消耗严重。所以我们在使用的时候,需要主动调用Dispose
方法来释放它。可以使用using如下所示:
using(var client = new HttpClient())
{
//do something with http client
}
网上说.NET Core版本的HttpClient存在比较多的问题(不过我自己一直在使用HttpClient做一些http请求),大家也可以HttpClientFactory,ASP.NET Core中使用HttpClientFactory官方教程:
前端使用Ajax-FormData对象上传文件:
注意点:
FormData:对象用以将数据编译成键值对,以便用
XMLHttpRequest
来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据(keyed data),而独立于表单使用。contentType:需设置为false,在Ajax中contentType 设置为false 是为了避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件。
processData:需设置为false,默认为true,表示以对象的形式上传的时候会默认把对象转化为字符串的形式上传。
<div class="text-center">
<p><input type="file" id="imageFile" onchange="uploadImage(this)" /></p>
</div> <div id="imageBox"> </div> <script type="text/javascript">
//图片上传
function uploadImage(fileObject) {
var formData = new FormData();
var files = $(fileObject).prop('files'); //获取到文件列表【$("#imageFile").get(0)通过id获取文件列表】
formData.append("files", files[0]);//图片文件流
console.log('formData=>>>', formData, files);
$.ajax({
async: true,
url:"@Url.Action("UploadImage", "ImageFileManage")",
type: 'post',
data: formData,
//https://segmentfault.com/a/1190000007207128?utm_source=tag-newest
//在 ajax 中 contentType 设置为 false 是为了避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件
contentType: false,
//告诉jQuery不要去处理发送的数据
processData: false,
success: function (res) {
console.log(res);
if (res.code == 0) {
$("#imageBox").append("<img width='100' height='100' src=" + res.msg.completeFilePath+">");
}
}
});
}
</script>
接收Ajax传递的文件流,并转化为转化字节类型:
/// <summary>
/// 图片文件管理
/// </summary>
public class ImageFileManageController : Controller
{
/// <summary>
/// 接收Ajax传递的文件流
/// </summary>
/// <param name="files">表单文件信息</param>
/// <returns></returns>
public IActionResult UploadImage(IFormFile files)
{
//var files = Request.Form.Files[0];//获取请求发送过来的文件
if (files.Length <= 0)
return Json(new { code = 1, msg = "请选择需要上传的文件~" }); var fileBytes = ReadFileBytes(files);
var fileExtension = Path.GetExtension(files.FileName);//获取文件格式,拓展名
var result = HttpClientHelper._.HttpClientPost("https://localhost:44347/FileUpload/SingleFileUpload", fileBytes, fileExtension, files.FileName); var resultObj = JsonConvert.DeserializeObject<UploadReponse>(result);
if (resultObj.IsSuccess)
{
return Json(new { code = 0, msg = resultObj });
}
else
{
return Json(new { code = 1, msg = resultObj.ReturnMsg });
}
} /// <summary>
/// 文件流类型转化字节类型
/// </summary>
/// <param name="fileData">表单文件信息</param>
/// <returns></returns>
private byte[] ReadFileBytes(IFormFile fileData)
{
byte[] data;
using (Stream inputStream = fileData.OpenReadStream())//读取上传文件的请求流
{
MemoryStream memoryStream = inputStream as MemoryStream;
if (memoryStream == null)
{
memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);
}
data = memoryStream.ToArray();
}
return data;
} } /// <summary>
/// 上传响应模型
/// </summary>
public class UploadReponse
{
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess { get; set; } /// <summary>
/// 结果
/// </summary>
public string ReturnMsg { get; set; } /// <summary>
/// 完整地址
/// </summary>
public string CompleteFilePath { get; set; }
}
向目标地址提交图片文件参数数据(HttpClient-上传multipart/form-data内容类型):
注意:
/// <summary>
/// Http网络请求帮助类
/// </summary>
public class HttpClientHelper
{
private static HttpClientHelper _httpClientHelper; public static HttpClientHelper _
{
get => _httpClientHelper ?? (_httpClientHelper = new HttpClientHelper());
set => _httpClientHelper = value;
} /// <summary>
/// 向目标地址提交图片文件参数数据
/// </summary>
/// <param name="requestUrl">请求地址</param>
/// <param name="bmpBytes">图片字节流</param>
/// <param name="imgType">上传图片类型</param>
/// <param name="fileName">图片名称</param>
/// <returns></returns>
public string HttpClientPost(string requestUrl, byte[] bmpBytes, string imgType, string fileName)
{
using (var httpClient = new HttpClient())
{
List<ByteArrayContent> byteArrayContents = new List<ByteArrayContent>(); var imgTypeContent = new ByteArrayContent(Encoding.UTF8.GetBytes(imgType));
imgTypeContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "imgType"
};
byteArrayContents.Add(imgTypeContent); var fileContent = new ByteArrayContent(bmpBytes);//填充图片文件二进制字节
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = fileName
};
byteArrayContents.Add(fileContent); var content = new MultipartFormDataContent();
//将ByteArrayContent集合加入到MultipartFormDataContent中
foreach (var byteArrayContent in byteArrayContents)
{
content.Add(byteArrayContent);
} try
{
var result = httpClient.PostAsync(requestUrl, content).Result;//post请求
return result.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}
模拟第三方上传文件接口,保存图片到服务端并返回文件预览完整地址:
关于.NET Core上传文件的后端服务接口可以参考我之前写过的文章:
/// <summary>
/// 单文件上传(Ajax,Form表单都适用)模拟第三方服务端接口
/// </summary>
/// <param name="file">表单文件信息</param>
/// <returns></returns>
public JsonResult SingleFileUpload(IFormFile file)
{
try
{
if (file != null)
{
var currentDate = DateTime.Now;
var webRootPath = _hostingEnvironment.WebRootPath;//>>>相当于HttpContext.Current.Server.MapPath("") var filePath = $"/UploadFile/{currentDate:yyyyMMdd}/"; //创建每日存储文件夹
if (!Directory.Exists(webRootPath + filePath))
{
Directory.CreateDirectory(webRootPath + filePath);
} //文件后缀
var fileExtension = Path.GetExtension(file.FileName);//获取文件格式,拓展名 //判断文件大小
var fileSize = file.Length; if (fileSize > 1024 * 1024 * 10) //10M TODO:(1mb=1024X1024b)
{
return Json(new { isSuccess = false, resultMsg = "上传的文件不能大于10M" });
} //保存的文件名称(以名称和保存时间命名)
var saveName = file.FileName.Substring(0, file.FileName.LastIndexOf('.')) + "_" + currentDate.ToString("HHmmss") + fileExtension; //文件保存
using (var fs = System.IO.File.Create(webRootPath + filePath + saveName))
{
file.CopyTo(fs);
fs.Flush();
} //完整的文件路径
var completeFilePath = Path.Combine(filePath, saveName); return Json(new { isSuccess = true, returnMsg = "上传成功", completeFilePath = completeFilePath });
}
else
{
return Json(new { isSuccess = false, resultMsg = "上传失败,未检测上传的文件信息~" });
} }
catch (Exception ex)
{
return Json(new { isSuccess = false, resultMsg = "文件保存失败,异常信息为:" + ex.Message });
}
}
项目完整示例:
参考文章:
https://www.cnblogs.com/willick/p/net-core-httpclient.html
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.http.httpclient?view=net-5.0
.NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)的更多相关文章
- 一个简单的QQ隐藏图生成算法 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传
一个简单的QQ隐藏图生成算法 隐藏图不是什么新鲜的东西,具体表现在大部分社交软件中,预览图看到的是一张图,而点开后看到的又是另一张图.虽然很早就看到过这类图片,但是一直没有仔细研究过它的原理,今天 ...
- .net core web api 与httpclient发送和接收文件及数据
客户端 HttpClient var url = $"https://localhost:44323/api/values/posttest?resource_source=yangwwme ...
- 通过jQuery和C#分别实现对.NET Core Web Api的访问以及文件上传
准备工作: 建立.NET Core Web Api项目 新建一个用于Api请求的UserInfo类 public class UserInfo { public string name { get; ...
- 循序渐进学.Net Core Web Api开发系列【5】:文件上传
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍通 ...
- .NET和.NET Core Web APi FormData多文件上传对比
前言 最近因维护.NET和.NET Core项目用到文件上传功能,虽说也做过,但是没做过什么对比,借此将二者利用Ajax通过FormData上传文件做一个总结,通过视图提交表单太简单,这里不做阐述,希 ...
- .NET Core Web APi大文件分片上传研究
前言 前两天发表利用FormData进行文件上传,然后有人问要是大文件几个G上传怎么搞,常见的不就是分片再搞下断点续传,动动手差不多也能搞出来,只不过要深入的话,考虑的东西还是很多.由于断点续传之前写 ...
- ASP.NET Core WEB API 使用element-ui文件上传组件el-upload执行手动文件文件,并在文件上传后清空文件
前言: 从开始学习Vue到使用element-ui-admin已经有将近快两年的时间了,在之前的开发中使用element-ui上传组件el-upload都是直接使用文件选取后立即选择上传,今天刚好做了 ...
- 在Mac下创建ASP.NET Core Web API
在Mac下创建ASP.NET Core Web API 这系列文章是参考了.NET Core文档和源码,可能有人要问,直接看官方的英文文档不就可以了吗,为什么还要写这些文章呢? 原因如下: 官方文档涉 ...
- Gitlab CI 自动部署 asp.net core web api 到Docker容器
为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成. ...
随机推荐
- 【Feign】Feign ,OpenFeign以及Ribbon之间的区别?
Ribbon Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件 Ribbon 可以用来做客户端负载均衡,调用注册中心的服务 Ribbon的使用需要代码里手动调用目标服务,请 ...
- SpringCloud之(豪猪)Hystrix限流、熔断、降级
Spring Cloud 微服务架构学习记录与示例 一.初识Hystrix Hystrix [hɪst'rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力.本文所说的Hystrix ...
- 从苏宁电器到卡巴斯基第14篇:我在苏宁电器当营业员 VI
我也过了一把讲师的瘾 由于iPhone已经成为了我们的主推产品,因此苏宁要求手机专区的每一个人,不论是自营还是厂促,都要对iPhone非常了解才可以.于是,督导也没有事先通知我,就直接让我给手机专区的 ...
- Java中常见的包
目录 JDK自带的包 第三方包 JDK自带的包 JAVA提供了强大的应用程序接口,既JAVA类库.他包含大量已经设计好的工具类,帮助程序员进行字符串处理.绘图.数学计算和网络应用等方面的工作.下面简单 ...
- Python中hashlib模块的使用
hashlib是 python 下一款与加密相关的库包,提供摘要算法:md5.sha1.sha224.sha256.sha384.sha512.blake2b.blake2s.sha3_224.sha ...
- 【pytest系列】- pytest测试框架介绍与运行
如果想从头学起pytest,可以去看看这个系列的文章! https://www.cnblogs.com/miki-peng/category/1960108.html 前言 目前有两种纯测试的测 ...
- .NET Core with 微服务 - 什么是微服务
微服务是这几年最流行的架构,说起架构不提微服务都不好意思跟人家打招呼.最近想要再梳理一下关于微服务的知识,并且结合本人的一些实践经验来做一些总结与分享.前面会分享一些概念性的东西,后面也会使用.net ...
- 17道APP测试面试题分享带参考答案
一.Android四大组件 Android四大基本组件:Activity.BroadcastReceiver广播接收器.ContentProvider内容提供者.Service服务. Activity ...
- 使用git rebase去掉无谓的融合
git pull 預設的行為是將遠端的 repo. 與本地的 repo. 合併,這也是 DVCS 的初衷,將兩個 branch 合併.但是,很多時候會發生以下這種情形: 這是因為,我們團隊的開發模式是 ...
- 如何在Mac OS X中开启VIM语法高亮和显示行号
VIM (Wikipedia图) Vim 是一款相当给力的源自UNIX平台的命令行文本编辑器,不过不给力的是,Mac OS X下并没有诸多Linux发行版上VIM那些牛逼哄哄的神马代码高亮显示啊,自动 ...