拓冰建站拓冰建站
首页 / 资讯中心 / 正文

解决.NET Web API大文件上传的413错误

1. 问题背景与现象分析在.NET Web API开发中文件上传功能是常见需求但默认配置下会遇到文件大小限制问题。当上传超过30MB左右的文件时通常会收到413 Request Entity Too Large错误。这个限制源于IIS和Kestrel服务器的默认配置也受ASP.NET Core框架自身的请求体大小限制影响。我最近在开发一个企业文档管理系统时就遇到了这个问题。客户需要上传大型设计图纸和视频文件单个文件经常超过100MB。测试时发现上传大文件直接失败浏览器控制台显示Failed to load resource: the server responded with a status of 413 (Request Entity Too Large)。2. 核心限制因素解析2.1 IIS服务器限制IIS默认限制请求大小为30MB(28.6MiB)。这个限制定义在applicationHost.config中system.webServer security requestFiltering requestLimits maxAllowedContentLength30000000 / /requestFiltering /security /system.webServer2.2 Kestrel服务器限制使用Kestrel时默认请求体大小限制也是30MB。这个限制在Program.cs中配置builder.WebHost.ConfigureKestrel(options { options.Limits.MaxRequestBodySize 100 * 1024 * 1024; // 100MB });2.3 ASP.NET Core MVC限制即使服务器允许大请求MVC框架自身也有限制services.ConfigureFormOptions(options { options.MultipartBodyLengthLimit 100 * 1024 * 1024; // 100MB });3. 完整解决方案实现3.1 开发环境配置对于IIS Express修改Properties/launchSettings.json{ iisSettings: { iisExpress: { maxRequestBodySize: 104857600 // 100MB } } }3.2 生产环境配置在web.config中添加system.webServer security requestFiltering requestLimits maxAllowedContentLength104857600 / !-- 100MB -- /requestFiltering /security /system.webServer3.3 控制器层实现文件上传接口示例[HttpPost] [RequestSizeLimit(100 * 1024 * 1024)] // 单个请求限制 public async TaskIActionResult UploadFile(IFormFile file) { if (file null || file.Length 0) return BadRequest(No file uploaded); var uploads Path.Combine(_environment.WebRootPath, uploads); if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads); var filePath Path.Combine(uploads, file.FileName); using (var stream new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } return Ok(new { file.FileName, Size file.Length }); }4. 高级配置与优化4.1 分块上传实现对于超大文件(1GB)建议实现分块上传[HttpPost] [DisableRequestSizeLimit] public async TaskIActionResult UploadChunk( [FromQuery] string fileId, [FromQuery] int chunkNumber, [FromQuery] int totalChunks, IFormFile chunk) { var tempDir Path.Combine(Path.GetTempPath(), uploads, fileId); Directory.CreateDirectory(tempDir); var chunkPath Path.Combine(tempDir, chunkNumber.ToString()); using (var stream new FileStream(chunkPath, FileMode.Create)) { await chunk.CopyToAsync(stream); } if (chunkNumber totalChunks) { await CombineChunks(fileId, tempDir); } return Ok(); }4.2 流式处理优化避免内存缓冲直接流式处理[HttpPost] public async TaskIActionResult StreamUpload() { var tempFile Path.GetTempFileName(); using (var stream new FileStream(tempFile, FileMode.Create)) { await Request.Body.CopyToAsync(stream); } return Ok(); }5. 常见问题排查5.1 配置未生效问题检查顺序确保web.config修改已部署检查Program.cs中的Kestrel配置验证Startup.cs中的FormOptions设置确认控制器没有更小的RequestSizeLimit5.2 内存不足问题大文件上传可能导致内存压力启用流式处理而非缓冲增加服务器内存考虑使用分块上传5.3 超时问题调整请求超时设置services.AddHttpClient(upload, c { c.Timeout TimeSpan.FromMinutes(30); });6. 安全注意事项始终验证文件类型var permittedExtensions new[] { .jpg, .png, .pdf }; var ext Path.GetExtension(file.FileName).ToLowerInvariant(); if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext)) { return BadRequest(Invalid file type); }设置合理的文件大小上限防止DoS攻击处理文件名安全var safeFileName Path.GetFileName(file.FileName) .Replace(\, ) .Replace(.., );考虑使用防病毒扫描上传的文件7. 性能优化建议启用压缩减少传输时间services.AddResponseCompression(options { options.EnableForHttps true; options.Providers.AddGzipCompressionProvider(); });使用CDN加速大文件分发实现断点续传功能监控上传性能app.Use(async (context, next) { var watch Stopwatch.StartNew(); await next(); watch.Stop(); logger.LogInformation($Upload took {watch.ElapsedMilliseconds}ms); });8. 测试验证方法使用Postman测试不同大小文件上传编写集成测试[Fact] public async Task Upload_LargeFile_ReturnsSuccess() { var file new MockIFormFile(); file.Setup(f f.Length).Returns(100 * 1024 * 1024); var result await controller.UploadFile(file.Object); Assert.IsTypeOkObjectResult(result); }使用ab或JMeter进行压力测试监控服务器资源使用情况9. 替代方案比较直接服务器上传 vs 云存储直传服务器上传简单可控但资源消耗大云存储直传减轻服务器负担需要额外集成Base64编码上传适合小文件增加约33%传输量WebSocket传输适合实时进度显示实现复杂度高10. 实际项目经验在电商项目中我们最终采用的方案是50MB文件直接上传到应用服务器50MB-1GB文件分块上传到临时存储后台合并1GB文件生成预签名URL直传对象存储关键教训不要信任Content-Length头客户端可能伪造临时文件要及时清理进度反馈对用户体验至关重要考虑移动网络不稳定的情况实现进度反馈的示例app.Use(async (context, next) { if (context.Request.Path.StartsWithSegments(/upload)) { var progress new ProgressReporter(context); context.Features.SetIHttpRequestBodyDetectionFeature(progress); } await next(); });
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门