童鞋,[HttpClient发送文件] 的技术实践请查收

童鞋,[HttpClient发送文件] 的技术实践请查收

1.荒腔走板

前几天有个童鞋在群里面问:怎么使用HttpClient发送文件

之前我写了一个ABP上传文件,主要体现的是服务端,上传文件的动作是由前端小姐姐完成的, 我还真没有用HttpClient编程方式发送过文件。

不过想来,Web协议都是一样的,类比前端发送文件,httpclient按照multipart/form-data媒体类型应该也是可以发送的。

花一个钟头阅读了MDN Web协议,写成了HttpClient发送文件的实例, 看官自取。

2.头脑风暴

我们跟随常见的表单上传文件思路来实现HttpClinet上传文件。

multipart/form-data是一种多部分的文档格式,每部分由边界线(一个由'--'开始的字符串)划分, 也是一种请求的媒体类型MIME

如下面的表单, 有三个待提交input表单字段


<form action="http://localhost:8000/" method="post" enctype="multipart/form-data">  <input type="text" name="myTextField">  <input type="checkbox" name="myCheckBox">Check</input>  <input type="file" name="myFile">  <button>Send the file</button></form>

中文件,点击[Send the file]按钮,提交表单,会发出如下请求

请观察由boundary划分的每个表单域和值, 其中myFile是一个文件表单域, 多一个Content-Type类型。

3.照葫芦画瓢

以上就是常规的Html表单上传文件的协议分析,回到本文主题, 这次会使用HttpClient编码形式发送只含有一个文件表单域的请求 (依旧利用的multipart/form-data媒体类型), 这也是下文的实现思路。

下面是httpclient向localhost:5000/upload地址上传文件, 服务器返回图片的base64编码字符串。

3.1 客户端

using System;using System.IO;using System.Net.Http;using System.Net.Http.Headers;using System.Text;using System.Threading.Tasks;namespace ConsoleApp3{    class Program    {        static readonly HttpClient client = new HttpClient();        static async Task Main()        {            try            {                byte[] bytes;                using (var bodyStream = new FileStream(@"D:\001.webp", FileMode.Open))                {                    using var m = new MemoryStream();                    await bodyStream.CopyToAsync(m);                    bytes = m.ToArray();                }                // 1. 准备文件表单域和值                var byteArrayContent = new ByteArrayContent(bytes);                byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");                // 2.  向MultipartFormDataContent插入准备好的文件表单域值, 注意MultipartFormDataContent是一个集合类型。                var response = await client.PostAsync("http://localhost:5000/upload", new MultipartFormDataContent(Guid.NewGuid().ToString())                    {                        { byteArrayContent, "uploadedFile", "\"001ggg.webp\""}                    });                response.EnsureSuccessStatusCode();                var responseBody = await response.Content.ReadAsStringAsync();                Console.WriteLine(responseBody);            }            catch (HttpRequestException e)            {                Console.WriteLine("\nException Caught!");                Console.WriteLine("Message :{0} ", e.Message);            }        }    }}
  • 请注意,我使用一个随机的GUID做为每个表单域的划分边界,这里我向MultipartFormDataContent只插入了一个文件表单阈值,这样就做到了HttpClient发送文件。
  • 文件表单域值: { byteArrayContent, "uploadedFile", "\"001ggg.webp\""} 中的参数2: 字段名称很重要,要与下面服务端的参数匹配。

3.2 服务端

上传文件的代码在 《》一文已经体现,本次截取接收文件上传的核心代码

 [Consumes("multipart/form-data")]        [Route("upload")]        [ProducesResponseType(typeof(Guid), 200)]        [HttpPost]        public async Task<string> UploadAsync(IFormFile uploadedFile)        {            var formFileName = uploadedFile.FileName;            if (!new[] { ".webp", ".webp", ".bmp" }.Any((item) => formFileName.EndsWith(item)))            {                throw new   NotImplementedException("您上传的文件格式必须为png、jpg、bmp中的一种");            }            byte[] bytes;            using (var bodyStream = uploadedFile.OpenReadStream())            {                using (var m = new MemoryStream())                {                    await bodyStream.CopyToAsync(m);                    bytes = m.ToArray();                }            }            var base64 = Convert.ToBase64String(bytes);            return base64;        }

码甲哥从不打诳语,启动客户端/服务端

3.3 授人以渔

成熟的技术必须有成熟的调试和监测手段!
成熟的技术必须有成熟的调试和监测手段!
成熟的技术必须有成熟的调试和监测手段!

每当做web开发出现阻塞的时候,我就掏出web利器: Fiddler。
跟着Fiddler去倒腾吧。

总结

  1. 对常规html表单上传文件,做源码级分析。
  2. 根据分析结果,HttpClient使用同样的姿势发送文件: 使用multipart/form-data(多部分表单媒体类型)发起上传请求。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部