.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官方教程:

在 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" 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上传文件的后端服务接口可以参考我之前写过的文章:

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

HttpClient 类 (System.Net.Http) | Microsoft Learn

IFormFile.OpenReadStream 方法 (Microsoft.AspNetCore.Http) | Microsoft Learn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452697.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

随机图论基础

一&#xff0c;随机图、随机图空间 1&#xff0c;随机图 一个n个点的无向图&#xff0c;最多有sn(n-1)/2条边。 每条边都有一定的概率存在&#xff0c;有一定概率不存在&#xff0c;那么每个图都有一个出现概率。 2&#xff0c;随机图空间 一共有2^s种不同的图&#xff0c…

LeAPI 后端接口开发 - 发布、下线接口

一、上线接口&#xff08;仅管理员&#xff09; 1. 校验请求参数 2. 判断&#xff08;测试&#xff09;接口是否可以调用 引入调用接口的客户端&#xff08;自己写的 SDK&#xff09;注入客户端实例调用接口 3. 修改数据库中接口的状态 /*** 上线&#xff08;发布&#xff…

Linux一些实用操作

学习笔记&#xff0c;记录以下课程中关于Linux的一些实用操作。黑马程序员新版Linux零基础快速入门到精通&#xff0c;全涵盖linux系统知识、常用软件环境部署、Shell脚本、云平台实践、大数据集群项目实战等_哔哩哔哩_bilibili 目录 1 各类小技巧&#xff08;快捷键&#xff…

[C#][opencvsharp]opencvsharp sift和surf特征点匹配

SIFT特征和SURF特征比较 SIFT特征基本介绍 SIFT(Scale-Invariant Feature Transform)特征检测关键特征&#xff1a; 建立尺度空间&#xff0c;寻找极值关键点定位&#xff08;寻找关键点准确位置与删除弱边缘&#xff09;关键点方向指定关键点描述子 建立尺度空间&#xff0…

Java基础之反射

反射目录&#xff0c;重点的顶层接口 1. 顶层接口1.1 概述&#xff08;重点&#xff09;1.2 Member1.3 AnnotatedElement1.4 Type1.4.1 概述&#xff08;重点&#xff09;1.4.2 GenericDeclaration1.4.3 TypeVariable1.4.4 ParameterizedType1.4.5 WildcardType上下界解释 1.4.…

Linux 驱动开发基础知识——设备树的语法驱动开发基础知识(九)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

SpringBoot 登录检验JWT令牌 生成与校验

JWT官网 https://jwt.io/ 引入依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>设置过期时间 LocalDateTime localDateTime LocalDateTime.now().…

前端开发中不同语言【react-i18next】

目录 查看并设置语言 单页面&#xff1a;html lang ​编辑 浏览器 自定义翻译&#xff1a;react-i18next 设置 模块&#xff1a;staticData.ts 散(重复利用)&#xff1a;命名空间.json 应用 准备 html标签 查看并设置语言 单页面&#xff1a;html lang 英语: <…

HTML+CSS:全景轮播

效果演示 实现了一个简单的网页布局&#xff0c;其中包含了五个不同的盒子&#xff0c;每个盒子都有一个不同的背景图片&#xff0c;并且它们之间有一些间距。当鼠标悬停在某个盒子上时&#xff0c;它的背景图片会变暗&#xff0c;并且文字会变成白色。这些盒子和按钮都被放在一…

【Java】【SSE】【VUE】实现调用千帆大模型,实现打字效果

没有废话。只有演示、和源码地址 效果演示 源码地址 qianfan-sse-demo: 基于https://gitee.com/codinginn/chatgpg-sse-demo-springboot-vue改动

电动汽车充放电V2G模型(matlab代码)

目录 1 主要内容 1.1 模型背景 1.2 目标函数 1.3 约束条件 2 部分代码 3 效果图 4 下载链接 1 主要内容 本程序主要建立电动汽车充放电V2G模型&#xff0c;采用粒子群算法&#xff0c;在保证电动汽车用户出行需求的前提下&#xff0c;为了使工作区域电动汽车尽可能多的消…

MySQL之谈谈MySQL里的日志

文章目录 前言一、SQL是如何做更新操作的二、MySQL中的redo log三、MySQL中的binlog四、聊聊两阶段提交总结 前言 上一章我们讲了一条SQL是如何做查询的&#xff0c;其中经历了许多步骤。这次来讲讲一条SQL是如何做更新操作的。 常有大佬说他可以把MySQL恢复到半个月内任意一秒…