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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:15:39