.NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)
需求背景:
拼多多优惠券 m.fenfaw.net
在需要通过服务端请求传递文件二进制文件流数据到相关的服务端保存时,如对接第三方接口很多情况下都会提供一个上传文件的接口,但是当你直接通过前端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官方教程:
在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求
前端使用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" οnchange="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上传文件的后端服务接口可以参考我之前写过的文章:
ASP.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://github.com/YSGStudyHards/DailyLearning
参考文章:
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
https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.iformfile.openreadstream?view=aspnetcore-5.0#Microsoft_AspNetCore_Http_IFormFile_OpenReadStream
.NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)相关推荐
- .NET Core Web APi大文件分片上传研究
[导读]前两天发表利用FormData进行文件上传.NET和.NET Core Web APi FormData多文件上传,然后有人问要是大文件几个G上传怎么搞,常见的不就是分片再搞下断点续传,动动手 ...
- .NET和.NET Core Web APi FormData多文件上传
[导读]最近因维护.NET和.NET Core项目用到文件上传功能,虽说也做过,但是没做过什么对比,借此将二者利用Ajax通过FormData上传文件做一个总结,通过视图提交表单太简单,这里不做阐述, ...
- ASP.NET Core Web API使用静态swagger.json文件
前言 ASP.NET Core Web API默认集成了Swashbuckle,可以在运行时显示Swagger UI: 而Swagger UI实际上是解析的动态生成的swagger.json: app ...
- core webapi缩略图_在ASP.NET Core Web API 项目里无法访问(wwwroot)下的文件
新建 ASP.NET Core Web API 项目 -- RESTFul 风格 Hello World! 一.创建一个空项目 请查看 新建 .NET Core 项目 -- Hello World! ...
- 如何测试ASP.NET Core Web API
在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...
- 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务
在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...
- 如何测试 ASP.NET Core Web API
在本文中,我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案.我们将了解使用单元测试进行内部测试,使用全新的 ASP .NET Core 的集成测试框架来进行外部测试 ...
- ASP.NET Core 实战:使用ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目
一.前言 这几年前端的发展速度就像坐上了火箭,各种的框架一个接一个的出现,需要学习的东西越来越多,分工也越来越细,作为一个 .NET Web 程序猿,多了解了解行业的发展,让自己扩展出新的技能树,对自 ...
- ASP.NET Core Web API
1.简单介绍 ASP.NET Core Web API 是 ASP.NET Core MVC 的一个功能.ASP.NET Core MVC 包含了对 Web API 的支持.可以构建多种客户端的 HT ...
最新文章
- 合肥工业大学—SQL Server数据库实验七:数据查询
- python的数值类型和运算符_Python中的基本数据类型和运算符,python
- vue暴露的全局方法_Vue中实现全局方法
- 上下左右连续滚动图片的JS代码
- ESP8266和MQTT
- 软件项目管理0728:项目经理的修养-干系人管理
- shell关闭指定进程
- html中怎样播放本地视频教程,【Axure9基础教程】内联框架如何引入本地音频 视频 HTML PDF等本地文件...
- android通讯录备份软件下载,通讯录同步助手
- Python+OpenCV:理解k近邻(kNN)算法(k-Nearest Neighbour (kNN) algorithm)
- day48 Pyhton 数据库Mysql 05
- 删除操作,提示“无法读取源文件或磁盘”,解决办法!
- Yoshua Bengio:深度学习的未来需要“探索高级认知的归纳偏置”
- GAN评价指标代码(FID、LPIPS、MS-SSIM)
- 给初学者:用VB写外挂 ———— 如何给外挂定义一组热键:红色警戒五项属性修改器VB版
- QQ界面的MSN聊天软件
- 天下难事必做于易 项目管理从简单做起(转)
- 数据结构-二叉树入门Go语言实现
- 信号量Semaphore了解过吗?
- 逻辑函数常用的描述方法及相互间的转化
热门文章
- JdbcTemplate DateTime转java.util.Date时区错误
- java什么都听过_【Java】程序员最大的悲哀是什么?
- 为什么韭菜一定要割三次后开花?
- 白话数字签名(3)——Web程序中的数字签名【转】
- 专治选择困难症——bandit算法
- 产品人应该点亮哪些技能树?如何夯实产品基本功?
- java毕业设计猎头公司业务管理系统的设计与实现源码+lw文档+mybatis+系统+mysql数据库+调试
- 迪丽热巴qq号是多少要真的?迪丽热巴的qq号是多少要真的在线的?
- salesforce 定时任务遇到的坑
- 蚂蚁金服的to B开放