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
相关产品推荐
相关产品推荐

