.Net Core 2.1慢速网络下文件下载失败问题求助
我用 .NET Core 2.1 写了一个 GET 方式的文件下载 REST API,正常网络环境下运行没问题,但在慢速网络区域的服务器上,用 Chrome 下载 20~25MB 的文件时,总会在 1~1.5 分钟内失败。我的代码如下:
[HttpGet("Download")] public IActionResult Download(string filePath) { byte[] fileData = null; System.IO.File.WriteAllBytes(filePath, datum); string fileName = $"File.zip"; Response.ContentLength = fileData.LongLength; return File(fileData, "application/octet-stream", fileName); }
我已经试过在 web.config 里加 requestTimeout="00:20:00",也在 API 里设置了 ContentLength,但都没用。想问下问题出在哪,该怎么解决?
结合你的代码和场景,问题主要出在这几个方面:
文件操作逻辑错误:代码里写了
System.IO.File.WriteAllBytes(filePath, datum);,但你是要实现下载功能,这里是把datum写入文件而非读取文件到内存——虽然你说正常网络下能运行,大概率是输入代码时的笔误,但这个逻辑如果没修正,实际运行时要么报错要么返回空数据,肯定会影响下载流程。全内存加载文件的弊端:你把整个文件读成
byte[]再返回,2025MB的文件虽然不算超大,但在慢速网络下,服务器需要把内存中的完整数据持续发送11.5分钟,期间不仅占用服务器内存,还刚好触发了.NET Core 2.1 Kestrel服务器的默认请求超时(默认约100秒,和你遇到的失败时间完全吻合)。web.config配置未生效:.NET Core 2.1默认用Kestrel作为服务器,
web.config里的requestTimeout是给IIS反向代理用的,直接对Kestrel服务器不生效,所以你修改后没有效果。
针对这些问题,一步步来修复:
1. 修正代码中的文件操作错误
先把错误的写入逻辑改成读取文件的正确代码(如果这是笔误的话):
byte[] fileData = System.IO.File.ReadAllBytes(filePath);
不过更推荐下面的流式传输方案,避免全内存加载的问题。
2. 改用流式传输(核心解决办法)
不要把整个文件加载到内存,而是用FileStream流式返回,这样内存占用极低,Kestrel会逐块发送数据,更适配慢速网络的长传输场景。修改后的代码如下:
[HttpGet("Download")] public IActionResult Download(string filePath) { // 先判断文件是否存在,避免抛出异常 if (!System.IO.File.Exists(filePath)) { return NotFound("请求的文件不存在"); } string fileName = $"File.zip"; // 打开文件流,指定异步读取、共享读取权限,缓冲区设为4096字节(通用最优值) var fileStream = new System.IO.FileStream( filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read, bufferSize: 4096, useAsync: true); // 直接返回文件流,框架会自动处理ContentLength和分块传输逻辑 return File(fileStream, "application/octet-stream", fileName); }
3. 配置Kestrel的超时参数
因为.NET Core 2.1的Kestrel默认请求超时是100秒,刚好是你遇到的失败时间,所以需要在Program.cs里增加Kestrel的超时配置:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .ConfigureKestrel(options => { // 设置连接保持超时,适配长传输场景 options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(20); // 设置整个请求的超时时间 options.Limits.RequestTimeout = TimeSpan.FromMinutes(20); });
4. (可选)检查客户端Chrome的下载设置
如果还是出现下载失败,可以检查Chrome的下载超时:在Chrome地址栏输入chrome://flags/#download-timeout,把超时时间调长一点(默认可能是几分钟),避免客户端主动中断连接。
内容的提问来源于stack exchange,提问作者HelloWorld

