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. [loj3329]有根树

    题目即求$\min_{C}\max(|C|,\min_{x\notin C}w_{x})$,考虑将$w$从大到小排序,即为$\min_{1\le k\le n}\max(k,w_{k+1})$ 考虑若 ...

  2. [noi1774]array

    容易想到树套树,但数据范围太大,会超时 考虑平衡树的作用,就是将这个区间内的所有数排序,所以可以离线+归并来处理,预处理复杂度$o(n\log n)$,然后考虑维护:1.删除:2.询问 删除操作维护可 ...

  3. Spring Cloud Gateway过滤器精确控制异常返回(实战,完全定制返回body)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 Spring Cloud Gateway应用 ...

  4. Linux系统编程之匿名管道

    1.进程间通信介绍 1.1 进程通信的基本概念 在之前我们已经学习过进程地址空间.Linux 环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不 ...

  5. CF1474E What Is It?

    考虑我们一定是每次构造最长的交换对. 那么就是\((1,n),(1,n - 1),...(1,\frac{n}{2} + 1)(\frac{n}{2},n)....(1,n)\)形式.

  6. (转载)Java里新建数组及ArrayList java不允许泛型数组

    java中新建数组: String[] s;//定义的时候不需要设置大小 s = new String[5];//为数组分配空间时就要设置大小   对于ArrayList, ArrayList< ...

  7. C#多个标题头合并

    protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e) { switch (e.Row.RowType) ...

  8. 巩固javaweb的第二十四天

    巩固内容: 提示用户信息 在验证失败之后通常需要提示用户错误信息,可以通过下面的代码完成: alert("地址长度大于 50 位!"); 当使用 alert 提示错误信息时,参数是 ...

  9. Go Robot

    1 <html> 2 <meta http-equiv="Content-Type" content="text/html; charset=utf-8 ...

  10. C++ 数字分类

           1012 数字分类 (20分) 输入格式: 每个输入包含 1 个测试用例.每个测试用例先给出一个不超过 1000 的正整数 N,随后给出 N 个不超过 1000 的待分类的正整数.数字间 ...