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

ASP.NET Core 6中HttpContext.Request.Body流读取上限仅4096字节的解决问询

解决ASP.NET Core 6中Request.Body每次仅读取4096字节的问题

问题核心

Stream.ReadAsync的返回值是当前流中可用的字节数,而非必须填满缓冲区。你看到的4096字节是Kestrel默认内部缓冲区大小,属于正常流读取行为,并非硬性限制。要实现按指定大小分块存入SQLite的目标,需通过累计读取凑够目标块大小的逻辑来解决,而非依赖单次读取填满缓冲区。

解决方案

1. 实现分块累计读取逻辑

针对多数文件3KB的场景,可将块大小设为4KB(避免小文件拆分多块),或保持1MB适配大文件。修改服务端代码,累计读取字节直到达到目标块大小(或文件结束)再写入数据库:

[HttpPost("UploadFile")]
[RequestSizeLimit(100000000000)]
public async Task<IActionResult> UploadFile()
{
    // 根据需求调整块大小,4KB适配多数小文件
    int TARGET_CHUNK_SIZE = 4 * 1024; 
    var buffer = new byte[TARGET_CHUNK_SIZE];
    int totalBytesInChunk = 0;
    int chunkNumber = 0;
    long totalBytesRead = 0;

    using (Stream stream = HttpContext.Request.Body)
    {
        int bytesRead;
        while ((bytesRead = await stream.ReadAsync(buffer.AsMemory(totalBytesInChunk, TARGET_CHUNK_SIZE - totalBytesInChunk))) > 0)
        {
            totalBytesInChunk += bytesRead;
            totalBytesRead += bytesRead;

            // 块填满或流结束时,处理当前块
            if (totalBytesInChunk == TARGET_CHUNK_SIZE || bytesRead == 0)
            {
                System.Diagnostics.Debug.WriteLine($"处理块 {chunkNumber},字节数:{totalBytesInChunk}");
                await ProcessChunk(buffer, totalBytesInChunk, chunkNumber, totalBytesRead - totalBytesInChunk);
                chunkNumber++;
                totalBytesInChunk = 0; // 重置块计数器
            }
        }

        // 处理最后一块不足TARGET_CHUNK_SIZE的情况
        if (totalBytesInChunk > 0)
        {
            System.Diagnostics.Debug.WriteLine($"处理最后一块 {chunkNumber},字节数:{totalBytesInChunk}");
            await ProcessChunk(buffer, totalBytesInChunk, chunkNumber, totalBytesRead - totalBytesInChunk);
        }
    }

    return Ok("文件上传并分块成功。");
}

2. 确认Kestrel与请求缓冲配置

在Program.cs中确保正确启用请求缓冲并调整Kestrel限制:

var builder = WebApplication.CreateBuilder(args);

// 配置请求缓冲
builder.Services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(options =>
{
    options.BufferBody = true;
    options.MemoryBufferThreshold = 1024 * 1024; // 1MB内存缓冲阈值
});

// 调整Kestrel参数
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.Limits.MaxRequestBodySize = 100000000000; // 与RequestSizeLimit保持一致
    serverOptions.Limits.MinRequestBodyDataRate = null;
    serverOptions.Limits.MinResponseDataRate = null;
});

// 其他服务配置...

var app = builder.Build();

// ASP.NET Core 6+ 默认已处理请求缓冲,无需额外添加UseRequestBuffering()

// 其他中间件配置...

app.Run();

3. 客户端代码优化(可选)

客户端StreamContent的缓冲区设置合理,建议用异步等待替代.Result避免阻塞:

var httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 2, 0);

var response = await httpClient.SendAsync(request);
// var responseContent = await response.Content.ReadAsStringAsync();
// Console.WriteLine(responseContent);

关键说明

  • 不要依赖ReadAsync一次填满缓冲区,流读取的本质是获取当前可用数据,累计读取才是实现指定大小分块的正确方式。
  • 4KB块大小可让多数3KB的小文件仅生成1条数据库记录,有效减少行数。
  • 若仍有读取异常,检查是否有日志、压缩类中间件干扰流读取行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:27:27