童鞋,[HttpClient發送文件] 的技術實踐請查收

1.荒腔走板

前幾天有個童鞋在羣裏面問:怎麼使用HttpClient發送文件?

之前我寫了一個ABP上傳文件,主要體現的是服務端,上傳文件的動作是由前端小姐姐完成的, 我還真沒有用HttpClient編程方式發送過文件。

不過想來,Web協議都是一樣的,類比前端發送文件,httpclient按照multipart/form-data媒體類型應該也是可以發送的。

花一個鐘頭閱讀了MDN Web協議,寫成了HttpClient發送文件的實例, 看官自取。

2.頭腦風暴

我們跟隨常見的表單上傳文件思路來實現HttpClinet上傳文件。

multipart/form-data是一種多部分的文檔格式,每部分由邊界線(一個由'--'開始的字符串)劃分, 也是一種請求的媒體類型MIME

如下面的表單, 有三個待提交input表單字段

Check

<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(多部分表單媒體類型)發起上傳請求。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章