Children's shoes, [HttpClient's technical practice of sending files] please check

Yesterday, there were children's shoes in the group and asked: how to send files using HttpClient?

01

Barren cavity walking board

I wrote one before< Upload file of ABP small test ox knife >, which is mainly reflected in the server. The action of uploading files is completed by the front-end little sister. I really haven't sent files by HttpClient programming.

However, the action of httpclient complies with the Web protocol. It should also be feasible to blindly guess that httpclient sends files according to the front-end multipart / form data media type.

I spent an hour reading the MDN Web protocol and wrote an example of HttpClient sending files, which is taken by the viewer.

02

Brainstorm

We follow the common idea of uploading files from forms to realize HttpClinet uploading files.

Multipart / form data is a media type composed of multipart form field values. Each part is divided by a boundary line (a string starting with '--').

As shown in the form below, there are three input form fields to be submitted

<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>

Select a file and click the [Send the file] button to submit the form. The following request will be sent

Please observe each form field and value divided by the boundary. myFile is a file form field, which needs to specify the content type separately.

03

Draw a ladle according to the gourd

The above is the protocol analysis of uploading files from conventional Html forms. Back to the topic of this article, this time, we will send a request containing only one file form field in the form of HttpClient encoding (still using the multipart / form data media type), which is also the implementation idea below.

The following is the base64 encoding string of the image returned by the server when the httpclient uploads the file to the localhost:5000/upload address.

3.1 client

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. Prepare file form fields and values
                var byteArrayContent = new ByteArrayContent(bytes);
                byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");

                // 2. Insert the prepared file form field value into MultipartFormDataContent. Note that MultipartFormDataContent is a collection type.
                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);
            }
        }
    }
}

• please note that I use a Random GUID as the boundary of each form field. Here, I only insert a file form threshold to MultipartFormDataContent, so that HttpClient can send files. • File form field value: {byteArrayContent, "uploadedFile", "\"001ggg.png \ ""} parameter 2: the field name is very important and should match the parameter name of the following server.

3.2 server

The code for uploading the file is in< Upload file of ABP small test ox knife >The article has reflected that the core code of intercepting and receiving file upload this time

[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("The file format you upload must be png,jpg,bmp One of");
     }
     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;
}

Code a never lies and starts the client / server

3.3 giving people the right to fish

Mature technology must have mature debugging and monitoring means!

Mature technology must have mature debugging and monitoring means!

Mature technology must have mature debugging and monitoring means!

Whenever there is a blockage in web development, I take out fiddler, a sharp web tool, and follow Fiddler to gallop.

Full text summary

1. Perform protocol level analysis on the function of uploading files from conventional html forms. 2. According to the analysis results, HttpClient uses the same gesture to send files: use multipart / form data (multi part form media type) to initiate an upload request.

[1] Media type MIME: https://developer.mozilla.org/zhCN/docs/Web/HTTP/Basics_of_HTTP/MIME_types

Added by rross46 on Wed, 22 Dec 2021 03:17:50 +0200