asp.net core webapi 默认不支持断点续传,需手动解析range头、安全seek文件流、设置206状态码及content-range、accept-ranges等响应头,并避免filestream过早释放或误用physicalfile。

ASP.NET Core WebAPI 默认不支持断点续传,FileStreamResult 和 PhysicalFile 都只返回 200 OK,无法响应 Range 请求头并返回 206 Partial Content。真要支持断点下载,必须手动解析请求头、定位文件流、设置响应状态与头信息。
怎么判断客户端发来了 Range 请求
服务端不能假设所有下载都走断点逻辑,得先检查请求是否带 Range 头。直接硬编码处理会把普通下载也当成分段请求,导致小文件也出错。
- 用
Request.Headers.TryGetValue("Range", out var rangeHeader)检查是否存在 - 别用字符串
.Contains("bytes=")粗暴匹配——有些代理或 CDN 会改写或注入头 - 推荐引用
Microsoft.Net.Http.Headers,调用RangeHeaderValue.Parse(rangeHeader)安全解析,它能自动识别bytes=1024-、bytes=-512等合法格式 - 如果解析失败或没
Range头,就按完整文件流程走(返回 200 + 全量内容)
如何安全地 Seek 并读取指定字节段
文件流必须支持随机访问(CanSeek == true),且不能在 using 块里创建后直接传给 FileStreamResult——那样流会在 action 返回前被释放,后续写响应时抛 ObjectDisposedException。
- 创建
FileStream时显式指定FileOptions.Asynchronous | FileShare.Read,否则并发请求可能卡死或报IOException: The process cannot access the file - 用
fileStream.Seek(startByte, SeekOrigin.Begin)定位,不要用Current——起始偏移是绝对位置,不是相对当前 - 读取长度必须严格等于
endByte - startByte + 1,多读或少读都会让客户端校验失败 - 缓冲区大小建议设为 8192 或 65536,太小(如 512)会导致 syscall 过多,太大(如 1MB)对 GC 不友好
为什么 PhysicalFile 不能用在 Controller 里做断点下载
PhysicalFile 看起来最省事,但它内部绕过了 WebAPI 的常规响应管道,直接交由 StaticFileMiddleware 处理——而该中间件只在 app.UseStaticFiles() 启用的路径下才启用 Range 支持。
- 在普通
[HttpGet]action 里调用PhysicalFile(path, mimeType),等价于返回一个没有Accept-Ranges: bytes头的 200 响应 - 客户端发来的
Range: bytes=1024-会被完全忽略,服务器照样发全部内容 - 真要用
PhysicalFile实现断点,必须把文件放到wwwroot下,并确保请求路径命中UseStaticFiles中间件(比如 URL 是/files/xxx.zip,且没被其他路由拦截) - 不推荐这种做法:它把业务文件暴露在静态资源路径下,权限控制弱,且无法统一记录日志或加鉴权逻辑
响应头和状态码哪些不能漏
只改状态码为 206 是不够的,客户端靠几个关键响应头协同判断是否可续传。漏掉任意一个,Chrome、curl 或移动端 SDK 都可能退化为全量重下。
- 必须设
Response.StatusCode = StatusCodes.Status206PartialContent,不能写206字面量 - 必须写
Content-Range头,格式为bytes {start}-{end}/{total},注意{end}是包含的(比如 1024–2047 表示共 1024 字节) - 必须写
Accept-Ranges: bytes,这是客户端决定是否发起后续Range请求的依据 - 别设
Content-Length——它应该等于实际返回的字节数,但Content-Range已隐含此信息;设了反而可能和 body 长度不一致,触发客户端校验失败 - 如果文件总大小未知(比如动态生成流),断点续传本身就不成立,别强行支持
最易被忽略的是流生命周期管理和 Accept-Ranges 头。很多人写了 206 和 Content-Range,却忘了加 Accept-Ranges: bytes,结果前端始终不发 Range 请求;还有人用 new FileStream(...) 包在 using 里,本地测试没事,一上压测环境就批量报“cannot access the file”。这些细节不处理好,断点续传就只是个幻觉。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










