.NET 6 API如何实现无缓冲文件流式上传 避免全量加载到内存或磁盘
.NET 6 下ASP.NET API无缓冲流式上传至Blob存储实现方案
完全可以实现,核心思路是放弃IFormFile的默认模型绑定——IFormFile默认触发的请求缓冲逻辑会把小于30MB的文件全量加载到内存,大于30MB的文件写入临时磁盘,只要跳过这套自动绑定逻辑,直接读取原始请求体流,就能实现全程无全量缓冲的流式传输。
具体实现步骤如下:
- 第一步:关闭接口的默认请求缓冲
给上传接口添加特性配置,关闭表单自动缓冲,同时配置合理的请求大小限制,注意接口参数里不能声明IFormFile/IFormFileCollection类型,否则会重新触发自动缓冲逻辑。[HttpPost("stream-upload")] // 生产环境建议替换为[RequestSizeLimit(10 * 1024 * 1024 * 1024)]设置10GB上限,避免恶意请求 [DisableRequestSizeLimit] [RequestFormLimits(MultipartBodyLengthLimit = long.MaxValue, BufferBody = false)] public async Task<IActionResult> StreamUploadToBlob(CancellationToken cancellationToken) { // 不要声明IFormFile类型参数 } - 第二步:手动解析multipart请求拿到原始文件流
用.NET内置的MultipartReader逐段读取请求体,跳过普通表单字段段,直接拿到文件段对应的原始请求流,这个流不会被框架全量缓冲,是边从网络读边前进的。// 从请求头提取multipart分隔符 var boundary = HttpContext.Request.GetMultipartBoundary(); if (string.IsNullOrWhiteSpace(boundary)) return BadRequest("非法的multipart/form-data请求"); var multipartReader = new MultipartReader(boundary, HttpContext.Request.Body); Stream uploadFileStream = null; string uploadFileName = string.Empty; MultipartSection section; while ((section = await multipartReader.ReadNextSectionAsync(cancellationToken)) != null) { if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var disposition)) continue; // 匹配文件段 if (disposition.DispositionType == "form-data" && !string.IsNullOrEmpty(disposition.FileName.Value)) { uploadFileStream = section.Body; uploadFileName = disposition.FileName.Value; break; } } if (uploadFileStream == null) return BadRequest("未检测到待上传文件"); - 第三步:直接流式对接Blob存储上传
拿到文件流后,不要调用ToArray()、ReadToEnd()这类会把流全量读入内存的方法,直接把流传给Blob SDK的上传方法即可——目前主流的Blob存储SDK(包括Azure Blob、S3兼容存储SDK)都支持直接接收流作为上传源,内部会按分块读取流内容上传,不会在API服务器本地缓存全量文件。
以Azure Blob存储为例:// BlobContainerClient建议通过依赖注入全局初始化,不要每次请求新建 var targetBlob = _blobContainerClient.GetBlobClient(uploadFileName); // 直接传入原始请求流,全程流式传输 await targetBlob.UploadAsync(uploadFileStream, cancellationToken: cancellationToken); return Ok(new { FileName = uploadFileName, BlobPath = targetBlob.Name });
注意事项
- 只要接口参数里出现
IFormFile相关类型,ASP.NET Core就会自动触发默认缓冲,前面配置的BufferBody = false会直接失效,这点一定要注意。 - 如果需要做文件大小校验,不要等流读完再判断,可以在流拷贝过程中累计已读取字节数,超过业务设定的阈值就直接抛出异常终止请求,避免浪费带宽。
- 如果服务前面挂了Nginx、IIS这类反向代理,需要同步关闭反向代理层的请求缓冲、调整最大请求体限制,否则反向代理会先把整个请求缓冲完再转发,服务端的无缓冲配置就不生效了。
- 不要把拿到的原始请求流包装成
MemoryStream或者写入本地临时文件,否则就失去了流式传输的意义。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

