5.8多部分表单内容

将请求的内容类型设置为 multipart/form-data 并发送多部分表单内容。

将请求的内容类型设置为 multipart/form-data 并发送多部分表单内容。

HTTP 声明式请求通过 MultipartAttribute 特性来设置多部分表单内容。相应的 HTTP 声明式提取器实现为 MultipartDeclarativeExtractor 类型,该类型负责解析 MultipartAttributeMultipartFormAttribute 特性并构建 HttpRequestBuilder 实例所需的多部分表单内容配置。

cs
public interface IHttpService : IHttpDeclarative{    // 添加常见表单项内容    [Post("https://furion.net/")]    Task<string> PostStringAsync(        [Multipart] int id,        [Multipart] string name,        [Multipart] object obj,        [Multipart] Stream stream,        [Multipart("bytes")] byte[] byteArray,  // 自定义表单名,还可以通过 FileName 属性指定文件名        [Multipart] StringContent content        [Multipart] MultipartFile file);    // 添加文件内容    [Post("https://furion.net/")]    Task<string> PostStringAsync(        [Multipart(AsFileFrom = FileSourceType.None)] string none, // 不做任何操作        [Multipart("files", AsFileFrom = FileSourceType.Path, ContentType = "image/jpeg")] string filePath,  // 从本地文件路径中添加,不传 Content-Type 将自动根据文件扩展名解析        [Multipart("files", AsFileFrom = FileSourceType.Base64String)] string base64String,  // 从 Base64 字符串文件中添加,不传 Content-Type 将自动根据文件扩展名解析        [Multipart("files", AsFileFrom = FileSourceType.Remote)] string remote); // 从互联网文件地址中添加,不传 Content-Type 将自动根据文件扩展名解析    // 添加对象内容,AsFormItem 为 false 时,对象属性会被解析并遍历,其属性将作为独立的表单项进行设置    [Post("https://furion.net/")]    Task<string> PostStringAsync([Multipart(AsFormItem = false)] object obj); // 推荐使用 [MultipartObject]    // 设置多部分表单内容的边界    [MultipartForm("--------------------")]    [Post("https://furion.net/")]    Task<string> PostStringAsync([Multipart] int id);    // 设置表单名称命名策略(转换器)    [Post("https://furion.net/")]    [MultipartForm(NamingPolicy = FormNamingPolicy.CamelCase)]    Task<string> PostStringAsync([MultipartObject] object obj);    // 冻结参数类型将被忽略    [Post("https://furion.net/")]    Task<string> PostStringAsync([Multipart] CancellationToken cancellationToken);}

包含文件(或二进制数据)的复杂表单#

在处理包含基础数据与文件(或二进制数据)的复杂表单时,可以使用 [MultipartObject] 特性标记对应的复杂类型。其中,文件字段推荐使用 MultipartFile 类型声明文件字段。示例接口定义如下:

cs
public interface IHttpService : IHttpDeclarative{    [Post("https://furion.net/")]    Task<string> PostStringAsync([MultipartObject] FormClass data);}

对应的模型类定义如下:

cs
public class FormClass  // 支持属性 [AliasAs] 定义别名{    public int Id { get; set; }    public string Name { get; set; }    public MultipartFile File { get; set; }    // public IFormFile File { get; set; }  // 注意:需要按照以下步骤配置}

注意:若使用 IFormFile 替代 MultipartFile,需确保已注册 FormFileContentProcessor。可通过全局调用 .AddHttpContentProcessors(() => [new FormFileContentProcessor()]) 来完成注册:

Startup.csProgram.cs 文件中,配置并注册 HttpRemote 服务,以启用 IFormFile 内容处理器功能:

cs
services.AddHttpRemote(builder =>{    builder.AddHttpContentProcessors(() => [ new FormFileContentProcessor() ]);});

通过这种方式,框架会自动将对象中的基本类型属性作为普通表单项提交,并将 MultipartFile 类型的属性作为文件上传内容进行正确编码和传输。

MultipartAttribute 标记的参数通过底层的 httpRequestBuilder.SetMultipartContent 方法进行设置,支持任意非冻结类型的参数。以下代码示例展示了如何使用 HttpRequestBuilder 达到相同配置效果:

cs
// 添加常见表单项内容HttpRequestBuilder.Post("https://furion.net")    .SetMultipartContent(multipart =>    {        multipart.AddFormItem(1, "id");        multipart.AddFormItem("Furion", "name");        multipart.AddFormItem(new { id = 1, name = "Furion" }, "obj");        multipart.AddStream(stream, "stream");        multipart.AddByteArray(bytes, "bytes");        multipart.Add(stringContent, "content");        multipart.AddFile(Multipart.CreateFromPath("路径"));    });// 添加文件内容HttpRequestBuilder.Post("https://furion.net")    .SetMultipartContent(multipart =>    {        multipart.AddFileAsStream(@"C:\Workspaces\httptest.jpg", "files", contentType: "image/jpeg");        multipart.AddFileFromBase64String("77u/5rWL6K+V5paH5Lu25YaF5a65", "files");        multipart.AddFileFromRemote("https://furion.net/img/furionlogo.png", "files");    });// 添加对象内容,AsFormItem 为 false 时,对象会被解析并遍历,其属性将作为独立的表单项进行设置HttpRequestBuilder.Post("https://furion.net")    .SetMultipartContent(multipart =>    {        multipart.AddObject(new { id = 1, name = "furion" });   // AsFormItem 为 false 相当于不设置表单名    });// 设置多部分表单内容的边界HttpRequestBuilder.Post("https://furion.net")    .SetMultipartContent(multipart =>    {        multipart.SetBoundary("--------------------");        multipart.AddFormItem(1, "id");    });// 添加复杂表单内容HttpRequestBuilder.Post("https://furion.net")    .SetMultipartContent(multipart =>    {        multipart.AddObject(new FormClass { Id = 1, Name = "furion", File = MultipartFile.CreateFromPath("文件路径") });    });

对比上述两种发送多部分表单内容的方法,HTTP 声明式请求方式的代码结构更加条理分明,更易于进行组织、维护和复用。

MultipartAttribute 包含以下构造函数和属性:

  • 构造函数

    • new():作用于参数,将参数作为多部分表单项内容。
    • new(name):作用于参数,将参数作为多部分表单项内容,支持设置表单名。
  • 属性

    • Name:表单名称(string 类型)。
    • FileName:文件的名称(string 类型)。
    • ContentType:内容类型(string 类型)。
    • ContentEncoding:内容编码(string 类型)。
    • AsFileFrom:表示将字符串作为多部分表单文件的来源(FileSourceType 类型),用于设置多部分表单文件内容,仅当参数为字符串类型时有效。FileSourceType 枚举包含以下选项:
      • None(默认值):不用作为文件的来源。
      • Path:作为本地文件路径。
      • Base64String:作为 Base64 字符串文件。
      • Remote:作为互联网文件地址。
    • AsFormItem:表示是否作为表单的一项(bool 类型),默认值为 true(作为),仅当参数为对象类型时有效。为 false(不作为) 时,对象会被解析并遍历,其属性将作为独立的表单项进行设置。

MultipartFormAttribute 包含以下构造函数和属性:

  • 构造函数

    • new():作用于方法,配置多部分表单内容属性。
    • new(boundary):作用于方法,配置多部分表单内容属性,支持设置多部分表单内容的边界。
  • 属性

    • Boundary:多部分表单内容的边界(string 类型)。默认值为:$"----{DateTime.Now.Ticks:x}"
    • OmitContentType:是否移除默认的多部分内容 Content-Typebool 类型)。默认值为 true
    • NamingPolicy:表单名称命名策略(转换器)(FormNamingPolicy 类型)。默认值为 FormNamingPolicy.None