Angular 5分块上传大文件至ASP.NET报MIME多部分流异常
解决大文件分块上传时的"MIME multipart stream 意外结束"错误
我之前也碰到过一模一样的问题,结合你的代码来看,主要是前端FileAPI的配置逻辑和后端的分块处理方式不匹配导致的,咱们一步步来修复:
前端代码核心问题修正
你的前端代码里有两个关键错误,直接导致了MIME流解析失败:
- 错误地用FormData包装文件传给FileAPI:FileAPI的
files字段应该直接传入原生文件对象,提前包装成FormData会打乱分块上传时的MIME结构,让后端无法正确识别每一块的边界。 - 注释了分块上传的核心配置:
chunkSize和formData是分块上传必须开启的配置,注释后FileAPI会以普通上传模式发送请求,和你想要的分块逻辑完全不符。
修改后的前端代码:
FileAPI.upload({ url: 'http://localhost:22166/api/lbx/upload', headers: { 'authorization': `Bearer ${this._svc.getToken()}` // 不要手动设置Content-Disposition,FileAPI会自动生成符合规范的请求头 }, // 直接传入文件对象,无需FormData包装 files: { file: this.fileToUpload }, // 开启FormData模式,适配后端的multipart处理逻辑 formData: true, // 设置分块大小,这里用1MB示例,可根据需求调整 chunkSize: 1.0 * FileAPI.MB, progress: function (evt){ console.log((evt.loaded / evt.total) * 100); }, complete: function (err, xhr){ if (err) { const message = JSON.parse(xhr.responseText).ExceptionMessage; parent.saving = false; parent.snack(message); } else { console.log('completed'); } } });
后端代码适配分块逻辑
后端默认的MultipartFormDataStreamProvider是为完整文件上传设计的,分块上传时每次请求只传递部分文件流,所以会触发"流不完整"的错误。需要调整代码来支持分块的接收与拼接:
[HttpPost] [Route("lbx/upload")] [EnableCors(origins: "*", headers: "*", methods: "*")] // 除非需要跨域携带Cookie,否则关闭SupportsCredentials,避免额外跨域问题 public async Task<IHttpActionResult> UploadLBXProject() { try { if (!Request.Content.IsMimeMultipartContent()) { const string errorMsg = "Request content is not MIME multipart content and is unsupported."; AppEventLog.Error(errorMsg); return StatusCode(HttpStatusCode.UnsupportedMediaType); } // 获取FileAPI自动传递的分块参数:文件唯一ID、当前块索引、总块数、文件名 var queryParams = Request.GetQueryNameValuePairs(); var fileId = queryParams.FirstOrDefault(p => p.Key == "fileId").Value; var chunkIndex = int.Parse(queryParams.FirstOrDefault(p => p.Key == "chunkIndex").Value); var totalChunks = int.Parse(queryParams.FirstOrDefault(p => p.Key == "totalChunks").Value); var fileName = queryParams.FirstOrDefault(p => p.Key == "fileName").Value; var root = HttpContext.Current.Server.MapPath("~/App_Data"); var targetFilePath = Path.Combine(root, fileName); // 处理分块写入:第一块创建新文件,后续块追加写入 using (var targetStream = new FileStream(targetFilePath, chunkIndex == 0 ? FileMode.Create : FileMode.Append)) { var provider = new MultipartFormDataStreamProvider(root); await Request.Content.ReadAsMultipartAsync(provider); var chunkFile = provider.FileData.First(); using (var chunkStream = new FileStream(chunkFile.LocalFileName, FileMode.Open)) { await chunkStream.CopyToAsync(targetStream); } // 删除临时生成的分块文件 File.Delete(chunkFile.LocalFileName); } // 如果是最后一块,返回上传完成的响应 if (chunkIndex == totalChunks - 1) { // 这里可以添加文件校验、解压等后续逻辑 return Ok(new { Message = "File uploaded successfully" }); } else { return Ok(new { Message = "Chunk uploaded successfully" }); } } catch (Exception ex) { AppEventLog.Error(ex.Message); return InternalServerError(ex); } }
额外注意事项
- 不要手动设置Content-Type:让FileAPI自动生成带正确边界的multipart请求头,否则后端会无法识别流的分割点。
- 目录权限:确保后端
App_Data目录有读写权限,否则会出现文件写入失败的隐性错误。 - 分块参数校验:后端可以增加对
chunkIndex、totalChunks等参数的合法性校验,避免非法请求干扰。
内容的提问来源于stack exchange,提问作者Luis Lavieri
相关产品推荐
相关产品推荐

