You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中用HttpClient高效传输30MB+DOCX文档的最优性能方案

30MB+ DOCX文档API传输毫秒级优化方案

问题背景

我需要在两个API之间传输一个超过30MB的DOCX文档,目前试了两种方案都达不到毫秒级要求:

  • JSON序列化传输:传输耗时约1秒
  • Multipart分块传输:传输耗时约0.5秒,但合并分块还要额外花300毫秒

以下是我已经尝试过的代码:

已尝试方案:JSON序列化方式

客户端代码

var templatebyteArray = System.IO.File.ReadAllBytes(@"C:\Users\rprajapati\Downloads\TableData-out.docx"); // template byte array 
var authorization = HttpContext.Request.Headers["Authorization"];
var Test30MBDoc = new Test30MBDoc { CurrentTime = starttime, DocArray = templatebyteArray };
var content = Serialize(Test30MBDoc);

using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, testUrl);
    request.Content = new StringContent(content, Encoding.UTF8, "application/json");
    request.Headers.Add("Authorization", authorization[0]);
    var response = await client.SendAsync(request);
}

服务端代码

[HttpPost]
[Route("receiver1")]
public async Task<IActionResult> Index(Test20MBDoc array)
{
    try
    {
        // transport time take around 1 second 
    }
}

已尝试方案:Multipart分块方式

客户端代码

var templatebyteArray = System.IO.File.ReadAllBytes(@"C:\Users\rprajapati\Downloads\TableData-out.docx");; // template byte array 

int MAX_SUB_SIZE = 5242880; // 5*1024*1024 == 5MB
MultipartFormDataContent multiPartContent = new MultipartFormDataContent();
int i = 1;
foreach (byte[] chunk in templatebyteArray.Chunk(MAX_SUB_SIZE))
{
    ByteArrayContent byteArrayContent = new ByteArrayContent(chunk);
    byteArrayContent.Headers.Add("Content-Type", "application/octet-stream");
    multiPartContent.Add(byteArrayContent, "byte content", $"chunk{i}");
    i++;
}

var authorization = HttpContext.Request.Headers["Authorization"];
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, testUrl);
    request.Content = multiPartContent;
    request.Headers.Add("Authorization", authorization[0]);
    var response = await client.SendAsync(request);
}

服务端代码

[HttpPost]
[Route("receiver")]
public async Task<IActionResult> Index()
{
    // transport time takes around 0.5 second but Need to convert chunks into template again it takes around 300 ms
}

最优优化方案

1. 直接传输原始字节流(无额外封装)

这是开销最小的方式,跳过JSON序列化、Multipart分块的额外处理,直接发送文件字节流,服务端直接读取原始流,省去序列化和分块合并的时间。

客户端代码

var authorization = HttpContext.Request.Headers["Authorization"];
// 用Stream读取文件,避免一次性加载到内存
using (var client = new HttpClient())
using (var fileStream = new FileStream(@"C:\Users\rprajapati\Downloads\TableData-out.docx", FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 8192, useAsync: true))
{
    var request = new HttpRequestMessage(HttpMethod.Post, testUrl);
    request.Content = new StreamContent(fileStream);
    // 指定二进制流类型
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    request.Headers.Add("Authorization", authorization[0]);
    
    var response = await client.SendAsync(request);
    response.EnsureSuccessStatusCode();
}

服务端代码

[HttpPost]
[Route("direct-receiver")]
public async Task<IActionResult> ReceiveDirect()
{
    // 直接读取请求体流,无需额外解析
    using (var targetStream = new MemoryStream())
    {
        await Request.Body.CopyToAsync(targetStream);
        targetStream.Position = 0;
        // 这里可以直接用targetStream处理DOCX,比如保存到文件或者直接传入处理逻辑
        // 示例:await using var fileStream = new FileStream("received.docx", FileMode.Create);
        // await targetStream.CopyToAsync(fileStream);
    }
    return Ok();
}

2. 开启HTTP压缩(进一步降低传输时间)

DOCX本身是压缩格式,但开启Gzip或Brotli压缩能进一步减少传输体积,降低网络耗时。

客户端配置(启用自动解压)

var handler = new HttpClientHandler
{
    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Brotli
};
using (var client = new HttpClient(handler))
{
    // 后续逻辑同直接字节流传输代码
}

服务端配置(ASP.NET Core)

在Program.cs中添加压缩中间件:

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    // 给二进制流添加压缩支持
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" });
    // 优先用Brotli压缩(比Gzip效率更高)
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

// 注册压缩中间件(要放在路由中间件之前)
app.UseResponseCompression();

3. 优化Multipart分块的合并逻辑(如果必须用分块)

如果业务上必须分块传输,优化服务端合并逻辑,避免不必要的内存拷贝,直接将分块流写入目标流:

优化后的服务端代码

[HttpPost]
[Route("optimized-receiver")]
public async Task<IActionResult> ReceiveOptimized()
{
    var form = await Request.ReadFormAsync();
    using (var targetStream = new MemoryStream())
    {
        foreach (var file in form.Files)
        {
            // 直接将分块流复制到目标流,无需先转成byte数组
            await file.CopyToAsync(targetStream);
        }
        targetStream.Position = 0;
        // 处理DOCX文档
    }
    return Ok();
}

方案对比

方案预估总耗时优势适用场景
直接字节流+压缩~200-300ms开销最小,传输效率最高无分块需求的场景
优化后Multipart分块~400-500ms支持分块,合并耗时降低需要分块校验/断点续传场景
原始JSON方式~1000ms无需修改解析逻辑小文件传输

内容的提问来源于stack exchange,提问作者user24973368

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:59:52