ASP.NET Core文件下载核心是FileStreamResult(适合大文件流式传输)和FileContentResult(适合小文件内存字节数组),选错易致内存暴涨或超时;FileStreamResult需确保路径存在与读取权限、用using或leaveOpen:false管理流,FileContentResult慎用于几MB内文件,ContentType须准确,前端跨域下载应使用带签名URL或form.submit避免blob限制。

ASP.NET Core 里实现文件下载,核心就两条路:FileStreamResult 适合大文件或流式生成场景,FileContentResult 适合小文件且内容已加载到内存;选错会导致内存暴涨或响应超时。
用 FileStreamResult 下载本地磁盘文件(推荐)
这是最常用也最稳妥的方式,不把整个文件读进内存,而是边读边传,对服务器压力小、支持断点续传基础能力。
- 必须确保文件路径真实存在且 Web 进程有读取权限(IIS 或 Linux 下常因权限被拒,错误信息是
UnauthorizedAccessException) - 响应头里的
Content-Disposition决定是「下载」还是「内嵌打开」,设为attachment; filename="xxx.pdf"才强制下载 - 别直接用
System.IO.File.OpenRead(path)—— 它不会自动释放,要用using包裹或返回FileStream并设leaveOpen: false
public IActionResult DownloadFile(string fileName)
{
var filePath = Path.Combine(_env.WebRootPath, "uploads", fileName);
if (!System.IO.File.Exists(filePath))
return NotFound();
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 8192, leaveOpen: false);
return new FileStreamResult(stream, "application/octet-stream")
{
FileDownloadName = fileName
};
}
用 FileContentResult 返回内存中字节数组(慎用)
只适合几 MB 以内的文件,比如导出的 Excel 报表(用 EPPlus 生成后转 byte[]),否则会瞬间吃光服务器内存。
-
FileContentResult构造函数接收byte[],不是string—— 别误用Encoding.UTF8.GetBytes("...")去传文本内容 - 如果源是
MemoryStream,记得先调.ToArray(),别传stream.GetBuffer()(可能含未使用垃圾字节) - 设置
ContentType要准确,例如 Excel 是application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,错设成text/plain会导致浏览器乱码或直接展示二进制
前端触发下载时遇到「跨域」或「无响应」怎么办
常见于 Vue/React 项目调用 API 后无法触发下载,本质是浏览器限制:用 fetch 或 axios 拿不到二进制流并自动触发保存,必须走 <a> 标签或 location.href。
- 不要用
axios.get("/api/download", { responseType: "blob" })然后手动创建 URL —— 在某些浏览器(尤其 Safari)会失败 - 正确做法:后端返回一个临时可访问的带签名 URL(如
/download/temp/abc123.xlsx),前端用location.href = url或动态创建<a href="..." download>触发 - 若必须走 POST 请求(如要传 JSON 参数),改用
form.submit()提交隐藏表单,服务端用[HttpPost]接收后重定向到真实下载地址
大文件下载卡住、超时、连接重置?检查这几个点
不是代码问题,大概率是中间件或基础设施拦住了。
- Kestrel 默认请求体上限是 30MB,但下载接口本身不受限;真正卡住常是因为反向代理(Nginx / IIS)设置了
client_max_body_size或maxAllowedContentLength—— 这些是针对上传的,下载不用改,但很多人误配 - IIS 上必须关闭
Response buffering:在web.config里加<httpProtocol><customHeaders><add name="X-Content-Type-Options" value="nosniff"/></customHeaders></httpProtocol>不够,得确认aspNetCore模块没启用缓冲 - Linux 部署时,Kestrel 的
KeepAliveTimeout默认 2 分钟,大文件下载超过这个时间会被断开 —— 需在Program.cs中显式延长:options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
文件下载看着简单,实际卡点全在边界:权限、头信息、代理配置、超时设置。写完接口一定要用真实大文件 + 移动网络模拟器压测一遍,别只在 localhost 点点就认为 OK。


















