asp.net core 的 request.form.files 默认将大文件全载入内存,因其依赖 multipartreader 且默认启用缓冲;需禁用自动模型绑定、设置 disablemultipartbuffering = true,并用 multipartreader 流式解析 multipart 数据边读边转存。

为什么 Request.Form.Files 会把大文件全塞进内存
ASP.NET Core 默认用 FormFile 处理上传,它底层依赖 MultipartReader,但一旦调用 file.OpenReadStream() 或 file.CopyToAsync(),框架就会把整个文件先缓存到内存(或临时磁盘),取决于 WebHostOptions.MemoryLimit 和 FormOptions.MultipartBodyLengthLimit 设置。这不是你代码写得不对,是默认行为本身就不适合 GB 级文件。
用 HttpContext.Request.Body 直接流式读取原始 multipart 数据
绕过 IFormFile,自己解析 multipart boundary,边读边转存。关键点:必须禁用自动模型绑定、关闭缓冲、手动控制读取节奏。
- 在
Startup.ConfigureServices中设options.DisableMultipartBuffering = true - Controller 方法参数去掉
[FromForm],改用HttpContext入参 - 检查
Request.ContentType是否以"multipart/form-data"开头,并提取boundary - 用
new MultipartReader(boundary, Request.Body)创建读取器,逐段调用ReadNextSectionAsync() - 对每个
section,检查ContentDisposition的FileName字段,匹配目标文件字段名(如"file") - 拿到对应 section 的
Body流后,直接await section.Body.CopyToAsync(outputStream)—— 这里outputStream可以是FileStream、HttpClient.PostAsync的请求体,或云存储 SDK 的上传流
MultipartReader 容易漏掉的坑
它不自动跳过 preamble(boundary 前的空白),也不校验 header 编码,出错时异常信息极简,常表现为 InvalidDataException 或静默截断。
- 务必用
Request.Headers["Content-Length"]校验总长度,防止客户端传一半就断连 - 设置
Request.EnableBuffering()仅在调试时临时开启,上线必须关 —— 否则又回到内存加载老路 -
boundary要从ContentType中安全提取:MediaTypeHeaderValue.Parse(Request.ContentType).Parameters.FirstOrDefault(p => p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase))?.Value - 不要用
StreamReader读 section body —— 它是二进制文件,不是文本;必须用Stream原始读取
上传到云存储(如 azure Blob / AWS S3)时怎么保持流式
核心是别把文件落地本地磁盘,而是让 MultipartReader 解出的 section.Body 直接作为上传 SDK 的输入流。多数 SDK 支持流式上传,但注意超时和分块策略。
- Azure Blob:用
BlobClient.UploadAsync(stream, new BlobHttpHeaders { ContentType = "application/octet-stream" }),内部会自动分块,无需你处理 - AWS S3:
PutObjectRequest.InputStream = section.Body,但需确保AutoCloseStream = false,否则 SDK 关闭流会导致后续 section 读取出错 - 若目标服务不支持流式(如某些旧版 FTP),只能落地临时文件 +
FileStream分块读取 + 手动删除,此时至少避免一次性ReadAllBytes
真正难的不是“怎么读”,而是边界条件:网络中断时如何续传、并发上传多个大文件时如何限流、用户取消上传时如何及时释放连接。这些没法靠一个 MultipartReader 解决,得结合前端 fetch 的 AbortController 和后端连接生命周期管理。