基于ASP.NET Core MVC 2通过HTTP协议上传不超过1GB的二进制数据
解决ASP.NET Core MVC 2中HttpClient大二进制文件上传的内存问题
嘿,我注意到你当前的实现是把整个文件一次性读进内存再发送——这对于最大1GB的文件来说绝对是个隐患,很容易触发内存溢出(OOM),毕竟把这么大的数据全塞到内存里,客户端和服务器的内存压力都会拉满。下面给你优化后的方案,全程基于流操作,不用加载整个文件到内存:
客户端改进代码
直接用StreamContent包装FileStream,让HttpClient逐流发送数据,而非一次性加载整个文件:
var client = new HttpClient(); // 打开文件流,指定异步模式和合理的缓冲区大小 using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)) { var content = new StreamContent(fs); // 设置二进制内容类型 content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // 发送POST请求,建议用异步方法避免阻塞 var response = await client.PostAsync("https://你的服务器地址/api/upload", content); // 确保请求成功,失败会抛出异常 response.EnsureSuccessStatusCode(); }
为什么这更好?
- 无需把整个文件读成
byte[],内存占用仅取决于缓冲区大小,而非文件总大小 StreamContent会自动处理ContentLength,不需要手动设置(你的原代码里这部分也没写完)- 异步操作更适合大文件传输,不会阻塞主线程
服务器端接收代码(ASP.NET Core MVC 2)
对应的,服务器端也要用流来接收,避免内存溢出:
[HttpPost("api/upload")] public async Task<IActionResult> ReceiveBinaryFile() { // 检查请求是否有内容 if (!Request.ContentLength.HasValue || Request.ContentLength == 0) { return BadRequest("未检测到上传的二进制内容"); } // 生成唯一文件名避免冲突,保存到指定目录 var uploadDir = Path.Combine(Directory.GetCurrentDirectory(), "uploaded-files"); Directory.CreateDirectory(uploadDir); var saveFileName = Guid.NewGuid().ToString(); var savePath = Path.Combine(uploadDir, saveFileName); // 把请求体流直接复制到文件流,全程不加载到内存 using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) { await Request.Body.CopyToAsync(fileStream); } return Ok(new { Message = "文件上传成功", SavedFilePath = savePath }); }
关键配置:解除ASP.NET Core的请求大小限制
ASP.NET Core默认有请求大小限制,1GB的文件肯定会触发拦截,需要在Startup.cs的ConfigureServices里添加配置:
public void ConfigureServices(IServiceCollection services) { // 配置表单请求大小限制(即使直接传流,也建议配置) services.Configure<FormOptions>(options => { options.MultipartBodyLengthLimit = 1073741824; // 1GB,单位是字节 }); // 配置Kestrel服务器的请求大小限制 services.Configure<KestrelServerOptions>(options => { options.Limits.MaxRequestBodySize = 1073741824; // 1GB }); // 其他原有配置... services.AddMvc(); }
额外注意事项
- 缓冲区大小:建议用4096或8192字节,这是操作系统的常见页大小,性能最优
- 错误处理:可以在客户端和服务器端添加
try-catch块,处理网络中断、文件读写失败等异常 - HttpClient复用:如果频繁上传文件,建议复用HttpClient实例,避免频繁创建销毁连接
内容的提问来源于stack exchange,提问作者Andrey Bushman
相关产品推荐
相关产品推荐

