.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容器
为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成. ...
随机推荐
- try catch 用法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- SSRF_FastCGI
SSRF_FastCGI 目录 SSRF_FastCGI FastCGI协议 SSRF ssrf + fastcgi 参考 FastCGI协议 简介 Fast CGI源自旧版本的CGI 路由/结构图 ...
- postgresql高级应用之合并单元格
postgresql高级应用之合并单元格 转载请注明出处https://www.cnblogs.com/funnyzpc/p/14732172.html 1.写在前面✍ 继上一篇postgresql高 ...
- 【python】Leetcode每日一题-二叉搜索迭代器
[python]Leetcode每日一题-二叉搜索迭代器 [题目描述] 实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器: BSTIterator(T ...
- Xshell6连Linux
一.安装 文件 链接: 提取码:8rmr 二.连Linux 名称填自己喜欢的.续之前,我们保持一样的名字.主机填IP,根据之前Linux填的静态IP去连接. 然后双击,连接 我们用最高权限,填root ...
- mybatis增删改返回的int是-2147482646,并不是想要返回结果
MyBatis发现更新和插入返回值一直为"-2147482646"的错误是由defaultExecutorType设置引起的,如果设置为batch,更新返回值就会丢失,返回结果就只 ...
- 微服务架构开发电商系统需要用Redis、ES和MQ吗?
如果不用什么很高大上的东西,就是有多个微服务就行这种技术架构会很难吗? 我看了一些视频,他们都用到了es.mq.redis的东西,我想不用这些东西,就简单的有多个服务,这样可行吗? 01 使用微服务你 ...
- SpringBoot系列——事件发布与监听
前言 日常开发中,我们经常会碰到这样的业务场景:用户注册,注册成功后需要发送邮箱.短信提示用户,通常我们都是这样写: /** * 用户注册 */ @GetMapping("/userRegi ...
- [MySQL数据库之数据库相关概念、MySQL下载安装、MySQL软件基本管理、SQL语句]
[MySQL数据库之数据库相关概念.MySQL下载安装.MySQL软件基本管理.SQL语句] 数据库相关概念 数据库管理软件的由来 数据库管理软件:本质就是个C/S架构的套接字程序. 我们在编写任何程 ...
- WIKI和JIRA-安装与使用
1.Wiki介绍1.1 Wiki(多人协作的写作系统)是一种超文本系统,这种超文本系统支持面向社群的协作式写作,即人人可编辑.在公司的项目管理中,可以把它当作文档管理和信息组织(Portlet)系统来 ...