ASP.NET Core 3.1 IIS托管下大于300MB文件下载返回0KB问题
问题修复方案
这个问题是代码生命周期错误+IIS托管环境默认大小限制/缓冲策略共同导致的,本地IIS Express默认缓冲阈值更高、调试环境不会主动回收未执行完的流资源,才会出现环境差异。
1. 修复代码逻辑错误
你当前代码存在两个会直接导致大文件返回空的问题:
- 把
HttpClient放在using块中声明:方法返回FileStreamResult时会立刻释放HttpClient实例,此时从SharePoint拉取的响应流还没完全写入客户端响应,大文件传输会被直接中断。小文件能正常下载是因为体积小,在流释放前已经全部载入内存缓冲。 - 调用
GetToken()时用了.Result同步阻塞:ASP.NET Core上下文里同步阻塞异步方法会造成线程池死锁,大文件传输耗时更长,触发死锁的概率远高于小文件。 - 不要每次请求新建
HttpClient实例,会造成端口耗尽问题,建议用IHttpClientFactory复用实例。
修正后的代码如下:
// 先在Startup.ConfigureServices中注册HttpClient:services.AddHttpClient(); public async Task<FileStreamResult> DownloadFile(string serverFileUrl, string fileName, [FromServices] IHttpClientFactory httpClientFactory) { var accToken = await GetToken(); var webUrl = "https://你的SharePoint站点根地址"; var accessToken = accToken.ToString(); var client = httpClientFactory.CreateClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var requestUrl = $"{webUrl}/_api/web/getfilebyserverrelativeurl('{serverFileUrl}')/$value"; var response = await client.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); var fileContent = await response.Content.ReadAsStreamAsync(); // 不需要手动Dispose客户端和流,FileResult执行完成后会自动释放响应流,HttpClient由工厂统一管理生命周期 return File(fileContent, System.Net.Mime.MediaTypeNames.Application.Octet, fileName, enableRangeProcessing: true); }
2. 补全IIS和框架大小限制配置
300MB正好是IIS、ASP.NET Core默认的大小阈值临界点,需要同步修改两处配置:
2.1 修改web.config配置
在项目发布后的web.config中添加如下配置,示例配置支持最大2GB文件传输,可根据需求调整数值:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <security> <requestFiltering> <!-- 配置IIS允许的最大请求长度,单位为字节,2147483648对应2GB --> <requestLimits maxAllowedContentLength="2147483648" /> </requestFiltering> </security> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments="你的应用入口dll名称.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess"> <handlerSettings> <!-- 关闭IIS层的响应缓冲,不要等大文件全部加载到内存再返回,直接流式传输 --> <handlerSetting name="bufferResponse" value="false" /> </handlerSettings> </aspNetCore> </system.webServer> </configuration>
2.2 配置服务端框架限制
在Startup.ConfigureServices中添加配置,取消Kestrel和MVC层的大小限制:
services.Configure<KestrelServerOptions>(options => { options.Limits.MaxRequestBodySize = null; // 不限制请求体大小 options.Limits.MaxResponseBufferSize = null; // 关闭Kestrel层响应缓冲 }); services.Configure<FormOptions>(options => { options.MultipartBodyLengthLimit = long.MaxValue; // 调整表单长度限制 });
如果需要针对单个接口放宽限制,可以在下载接口方法上添加特性:[RequestSizeLimit(long.MaxValue)]
3. IIS站点额外检查项
- 打开对应IIS站点的「输出缓存」设置,关闭下载路径的缓存规则,避免大文件被缓存策略截断
- 检查站点对应应用程序池的高级设置,将「启用32位应用程序」设为
False,32位进程内存上限不足会导致大文件流处理中断 - 确认应用程序池标识对站点目录、系统临时目录有读写权限,流式传输过程中需要临时目录存储分片数据
内容的提问来源于stack exchange,提问作者Anel
相关产品推荐
相关产品推荐

