.NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)

简介: .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内容类型):

注意:

1336199-20210607212435819-411275683.png

1336199-20210607212749930-986097520.png

 /// <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 });
            }
        }


相关文章
|
1月前
|
开发框架 前端开发 JavaScript
ASP.NET Web Pages - 教程
ASP.NET Web Pages 是一种用于创建动态网页的开发模式,采用HTML、CSS、JavaScript 和服务器脚本。本教程聚焦于Web Pages,介绍如何使用Razor语法结合服务器端代码与前端技术,以及利用WebMatrix工具进行开发。适合初学者入门ASP.NET。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
4天前
|
人工智能 搜索推荐 API
自学记录鸿蒙API 13:实现人脸比对Core Vision Face Comparator
在完成文本识别和人脸检测项目后,我深入学习了HarmonyOS Next API 13中的Core Vision Face Comparator API,开发了一个简单的人脸比对工具。该API能进行高精度人脸比对并给出相似度评分,应用场景广泛,如照片分类、身份认证、个性化服务等。通过初始化服务、加载图片、实现比对功能和构建用户界面,最终实现了可靠的人脸比对功能。未来计划将此技术应用于更复杂的场景,如照片管理和个性化服务,并探索与其他AI能力的结合。如果你也对人脸比对感兴趣,不妨从简单的比对功能开始,逐步实现自己的创意!
94 61
|
2天前
|
API 开发者 UED
自学记录鸿蒙API 13:PreviewKit从文件预览到应用开发
通过学习API 13,我深入研究了**PreviewKit(文件预览服务)**。该模块支持快速预览多种文件类型(文本、图片、视频、音频、PDF等),为文件管理类应用提供系统级支持。本文分享了从搭建开发环境到实现单文件和多文件预览的全过程,并介绍了如何构建一个实用的文件预览助手应用。通过实践,不仅掌握了技术细节,还提升了个人开发能力。希望这些经验能为其他开发者带来启发与帮助。
32 10
自学记录鸿蒙API 13:PreviewKit从文件预览到应用开发
|
4天前
|
运维 前端开发 C#
一套以用户体验出发的.NET8 Web开源框架
一套以用户体验出发的.NET8 Web开源框架
一套以用户体验出发的.NET8 Web开源框架
|
22天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
53 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
5天前
|
人工智能 自然语言处理 文字识别
自学记录鸿蒙API 13:实现智能文本识别Core Vision Text Recognition
在完成语音助手项目后,我尝试了HarmonyOS Next API 13中的Core Vision Text Recognition API,体验其强大的文本识别功能。该API支持多语言高精度识别,能快速将图像中的文本提取为结构化信息,适用于文档扫描、票据管理和实时翻译等场景。通过权限配置、初始化服务、实现识别功能和构建用户界面,我完成了文本识别应用的开发,并探索了性能优化与功能扩展。鸿蒙生态的强大支持让开发者能更便捷地实现复杂功能。未来计划将此技术应用于实际项目,如票据管理或实时翻译工具。如果你也对文本识别感兴趣,不妨一起探索!
61 11
|
4天前
|
人工智能 监控 安全
自学记录鸿蒙 API 13:骨骼点检测应用Core Vision Skeleton Detection
骨骼点检测技术能够从图片中识别出人体的关键骨骼点位置,如头部、肩部、手肘等,广泛应用于运动健身指导、游戏交互、医疗辅助、安全监控等领域。我决定深入学习HarmonyOS Next API 13中的Skeleton Detection API,并开发一个简单的骨骼点检测应用。通过理解API核心功能、项目初始化与配置、实现检测功能、构建用户界面,以及性能优化和功能扩展,逐步实现这一技术的应用。未来计划将其应用于健身指导和智能监控领域,探索与其他AI能力的结合,开发更智能的解决方案。如果你也对骨骼点检测感兴趣,不妨一起进步!
129 9
|
5天前
|
人工智能 监控 安全
自学记录鸿蒙 API 13:实现人脸检测 Core Vision Face Detector
本文介绍了基于HarmonyOS Next API 13中的Core Vision Face Detector API实现人脸检测小应用的过程。通过研究发现,该API不仅支持人脸检测框的定位,还能识别关键点(如眼睛、鼻子和嘴角位置)及人脸姿态信息。文章详细记录了开发历程,包括项目初始化、权限配置、图像加载与人脸检测、用户界面设计,以及性能优化和功能扩展的思路。应用场景涵盖身份验证、照片管理和实时交互等。未来计划将技术应用于智能照片管理工具,提供更高效的照片分类体验。欢迎对人脸检测技术感兴趣的读者一起探讨和进步。
79 7
|
2月前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结