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

.NET MVC文件返回端点随机失败问题排查求助

问题:大文件下载随机失败,使用FileOptions.DeleteOnClose

我实现了一个MVC端点用于返回文件,并且在客户端下载完成后在服务器端删除该文件。我的实现参考了Stack Overflow上的方案,区别在于我的端点返回的是纯文本文件。

服务器端代码

[Authorize, HttpGet]
public FileResult DownloadLogFile(string fileName)
{
    var path = Path.Combine(this.logFilesRoot, fileName);
    var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
    return File(fs, MediaTypeNames.Text.Plain, fileName);
}

这段代码大部分情况下正常工作,但大于40MB的大文件会偶尔随机下载失败,Chrome报错截图如下:
下载失败

我也在Firefox和Edge中测试过,同样出现问题,所以不是浏览器的问题。

环境细节

  • .NET 7
  • ASP.NET Core 6
  • Windows操作系统

编辑更新

我已经将端点方法改为POST,但问题依旧。现在JS的fetch方法会抛出net::ERR_CONNECTION_RESET 200异常。

客户端代码

const redirectToLogFile = (fileName: SignalR.IDownloadableLogFileDetails): void => {
    const url = `${Utils.root}home/DownloadLogFile/${fileName.FileName}`;
    fetch(url, { method: "POST" })
    .then(response => response.blob())
    .then(blob => {
        const a = document.createElement("a");
        a.href = window.URL.createObjectURL(blob);
        a.download = fileName;
        a.click();
    })
    .catch(err => console.log(err));
}

可能的失败原因分析

  1. FileShare.None引发的文件锁定冲突
    使用FileShare.None会对文件施加独占锁定,若服务器端有其他进程(如日志写入程序)尝试访问该文件,或ASP.NET Core请求处理中出现意外重试/并发访问,就会触发文件访问失败,进而中断下载。大文件下载耗时更长,这类冲突的发生概率也更高。

  2. FileOptions.DeleteOnClose的时机偏差
    Windows系统中,标记DeleteOnClose的文件会在文件流关闭时被删除。如果ASP.NET Core响应管道在文件未完全发送给客户端时就提前关闭了文件流(比如请求超时、连接中断),文件会被提前删除,客户端下载到不完整内容后触发错误。大文件传输时间更长,更易出现这类情况。

  3. 请求超时设置不足
    ASP.NET Core默认请求超时时间可能不足以支撑大文件下载,若40MB以上文件的下载耗时超过默认超时阈值,服务器会主动断开连接,引发ERR_CONNECTION_RESET错误。

  4. 内存/缓冲区限制
    直接返回FileStream时,ASP.NET Core可能会尝试将文件内容缓冲到内存中。大文件会导致内存压力过高,进而引发意外的连接中断或进程异常。

解决方案建议

  • 调整文件共享模式:将FileShare.None改为FileShare.Read,允许其他进程读取文件(无写入需求时),降低锁定冲突概率。
  • 改用后台删除逻辑:放弃DeleteOnClose,改为下载完成后通过后台任务(如Hangfire、IHostedService)删除文件。可在响应完成后记录待删除文件路径,由后台服务定期清理已完成下载的文件。
  • 延长请求超时时间:在Program.cs中配置更长的请求超时,示例代码:
    builder.WebHost.ConfigureKestrel(options =>
    {
        options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(5);
        options.Limits.IdleTimeout = TimeSpan.FromMinutes(5);
    });
    
  • 启用流式传输:返回FileStreamResult并明确设置EnableRangeProcessing = true,确保ASP.NET Core采用流式传输而非将整个文件缓冲到内存,同时避免使用可能触发缓冲的中间件。
  • 优化客户端下载逻辑:客户端用fetch获取blob的方式对大文件来说内存占用过高,可改用直接跳转下载链接的方式(如设置window.location.href),让浏览器直接处理下载,降低前端内存压力。

内容的提问来源于stack exchange,提问作者LA.27

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 03:32:31