1.荒腔走板

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

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

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

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

2.头脑风暴

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

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

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

Check

Send the file


<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.png", 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.png\""}
}); 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.png\""} 中的参数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[] { ".png", ".jpg", ".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(多部分表单媒体类型)发起上传请求。

童鞋,[HttpClient发送文件] 的技术实践请查收的更多相关文章

  1. 使用HttpClient发送文件流到服务器端

    适用场景:网络绝对路径的URL文件或图片,不存储到本地,转换成stream,直接使用HTTPClient传送到SpringBoot的服务端,将文件存储下来,并返回一个文件地址.目前分层架构的系统越来越 ...

  2. httpclient 发送文件和字符串信息

    HttpPost httpPost = new HttpPost(url);                MultipartEntity reqEntity = new MultipartEntit ...

  3. Android系列之网络(一)----使用HttpClient发送HTTP请求(通过get方法获取数据)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  4. 子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

    本文原文内容来自InfoQ的技术分享,本次有修订.勘误和加工,感谢原作者的分享. 1.前言 自从2018年8月20日子弹短信在锤子发布会露面之后(详见<老罗最新发布了“子弹短信”这款IM,主打熟 ...

  5. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

    本文来自融云技术团队原创分享,原文发布于“ 融云全球互联网通信云”公众号,原题<IM 即时通讯之链路保活>,即时通讯网收录时有部分改动. 1.引言 众所周知,IM 即时通讯是一项对即时性要 ...

  6. 从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

    本文由马蜂窝技术团队电商交易基础平台研发工程师"Anti Walker"原创分享. 一.引言 即时通讯(IM)功能对于电商平台来说非常重要,特别是旅游电商. 从商品复杂性来看,一个 ...

  7. 灵雀云Istio技术实践专题整理

    Istio技术实践专题(1) Service Mesh Istio 基本概念和架构基础 Istio被称作Kubernetes的最佳云原生拍档.从今天起,我们推出"Istio技术实践" ...

  8. Android系列之网络(三)----使用HttpClient发送HTTP请求(分别通过GET和POST方法发送数据)

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  9. (一)----使用HttpClient发送HTTP请求(通过get方法获取数据)

    (一)----使用HttpClient发送HTTP请求(通过get方法获取数据) 一.HTTP协议初探: HTTP(Hypertext Transfer Protocol)中文 “超文本传输协议”,是 ...

随机推荐

  1. 如何看待 SAE 在2014 年 3 月 24 日发生的的大面积宕机事故?

    3 月 24 日晚间大约 23 点左右,新浪云 SAE 一处核心机柜掉电,导致 SAE 平台下大量应用无法正常访问,并在 10 小时后才陆续修复.这次事故暴露 SAE 的哪些缺陷?SAE 运维人员又是 ...

  2. [nowcoder5667G]Greater and Greater

    令$f[i][j]$表示前i个数的后j位能否匹配b的前j位,有转移$f[i][j]=f[i-1][j-1] \ \&\  [b_{j}\le a_{i}]$ 将$g[i][j]=[b_{j}\ ...

  3. Ubuntu下的磁盘管理

    采用fat的磁盘存储,插入后采用相同命令会出现sdb和sdb1 sdb:磁盘 sdb1:磁盘分区标号为1 命令 df:显示磁盘使用情况 du:查询某个文件的大小读 du-h 或du -h --max- ...

  4. idea提交代码好习惯-代码格式化

    提交代码的时候,勾选这个可以格式化提交的代码,非常好! reformat code

  5. Go语言核心36讲(Go语言实战与应用十九)--学习笔记

    41 | io包中的接口和工具 (下) 上一篇文章中,我主要讲到了io.Reader的扩展接口和实现类型.当然,io代码包中的核心接口不止io.Reader一个. 我们基于它引出的一条主线,只是io包 ...

  6. CF713C Sonya and Problem Wihtout a Legend

    考虑我们直接选择一个暴力\(dp\). \(f_{i,j} = min_{k<=j}\ (f_{i - 1,k}) + |a_i - j|\) 我们考虑到我们直接维护在整个数域上\(min(f_ ...

  7. 洛谷 P3994 高速公路(斜率优化)

    题目链接 题意:给出一棵树,\(1\) 号点为根,边上有边权. 每个点有两个参数 \(p_i,q_i\) 如果你想从 \(i\) 号点到与其距离为 \(d\) 的 \(j\) 号点,那么你需花费 \( ...

  8. Python基础之流程控制while循环

    目录 1. 语法 2. while+break 3. while+continue 4. while+else 1. 语法 最简单的while循环如下: ''' while <条件>: & ...

  9. typedef 的用法

    [2]typedef (1)在C语言中,允许使用关键字typedef定义新的数据类型 其语法如下: typedef <已有数据类型> <新数据类型>; 如: typedef i ...

  10. 动态生成多个选择项【c#】

    <asp:CheckBoxList ID="cbxLabelList" runat="server" RepeatColumns="10&quo ...