直接用HttpPostedFileBase或IFormFile上传大文件会失败,因ASP.NET默认请求体限制(30MB/.NET Framework或128MB/.NET6+),且整文件加载内存易致OutOfMemoryException或400/413错误,且无分片则无法实现断点续传。

为什么直接用 HttpPostedFileBase 或 IFormFile 上传大文件会失败
因为 ASP.NET(包括 .NET Core / .NET 5+)默认限制单次请求体大小为 30MB(.NET Framework)或 128MB(.NET 6+),且整个文件会先加载进内存或临时磁盘,超大文件(如 2GB 视频)极易触发 OutOfMemoryException 或 400/413 错误。更关键的是:没做分片,就根本谈不上断点续传。
HttpClient 分片上传时如何构造合法的 multipart/form-data 请求
后端不接受“裸”二进制流,必须模拟浏览器表单提交格式。每一片要作为独立 multipart/form-data 的一部分,带明确字段名和元信息:
- 必需字段:
file(文件片内容)、filename(原始文件名)、chunkIndex(从 0 开始)、totalChunks、identifier(唯一标识,如md5(filename + filesize)) - 不要把整块文件读进
byte[]再传——用FileStream+StreamContent流式读取,避免内存爆掉 - 务必设置
HttpClient.DefaultRequestHeaders.ExpectContinue = false,否则某些服务器(如 Nginx)会因 Expect: 100-continue 超时拒绝分片
示例关键片段:
var content = new MultipartFormDataContent(); content.Add(new StringContent(chunkIndex.ToString()), "chunkIndex"); content.Add(new StringContent(totalChunks.ToString()), "totalChunks"); content.Add(new StringContent(identifier), "identifier"); content.Add(new StreamContent(fileStream), "file", "blob"); // 注意第三个参数是文件名(可固定为"blob")
后端合并前必须校验哪些关键状态
仅靠前端传来的 chunkIndex 和 totalChunks 不足以安全合并。服务端需主动维护上传上下文:
- 每个
identifier对应一个临时上传记录,存于内存(小流量)或 Redis(高并发),包含已接收的chunkIndex集合、总大小、最后更新时间 - 收到新分片时,检查是否重复(
chunkIndex已存在)、是否越界(chunkIndex >= totalChunks)、是否超时(最后更新距今 > 24h) - 合并动作不能在 HTTP 请求中直接执行——用后台任务(如
BackgroundService或 Hangfire)异步触发,防止请求超时;合并前再次按identifier重查所有分片文件是否存在且完整
断点续传依赖的客户端状态怎么持久化又不泄漏
浏览器刷新后,前端必须能知道“刚才传到第几片了”。不能把 identifier 或分片列表存在 URL 或 localStorage 明文里(有安全和一致性风险):
- 推荐方案:上传开始时,前端调用
/api/upload/init获取服务端返回的uploadId(UUID)和signature(HMAC-SHA256(uploadId + timestamp + secret)) - 后续所有分片请求带上
uploadId和签名,服务端验证签名时效性(如 5 分钟内) - 客户端将
uploadId+ 当前chunkIndex存入 IndexedDB,支持跨标签页恢复;每次上传前先 GET/api/upload/status?uploadId=xxx拉取已传成功的分片索引数组
真正难的不是切片,而是让服务端能无歧义地识别“这是同一个文件的同一片”,并且在任意节点崩溃后仍能通过最小元数据重建上下文——这要求前后端对 identifier、uploadId、分片哈希(可选)三者的生成和校验逻辑完全一致。


















