童鞋,[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.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去倒騰吧。
總結
- 對常規html表單上傳檔案,做原始碼級分析。
- 根據分析結果,HttpClient使用同樣的姿勢傳送檔案: 使用
multipart/form-data
(多部分表單媒體型別)發起上傳請求。
本文來自部落格園,作者:{有態度的馬甲},轉載請註明原文連結:https://www.cnblogs.com/JulianHuang/p/15697845.html
歡迎關注我的原創技術、職場公眾號, 加好友談天說地,一起進化