spring mvc可通过http range协议实现断点续传:解析range头计算偏移量,返回206 partial content及content-range等响应头,配合filechannel或bufferedinputstream流式分段读写,避免内存加载,同时注意416错误处理与nginx代理配置。

Spring MVC 本身不直接提供断点续传功能,但可以通过标准 HTTP 协议机制(Range 请求和206 Partial Content 响应)配合文件流式读取来实现。核心在于正确解析 Range 头、计算偏移量、设置响应状态与头信息,并分段输出文件内容。
1. 支持 Range 请求的 Controller 实现
需要手动处理 Range 请求头,读取指定字节范围,返回 206 Partial Content;若无 Range 头,则按常规方式返回完整文件(200 OK)。
- 从请求中提取
Range头(格式如bytes=0-1023或bytes=500-) - 校验范围是否合法(不能越界、不能负数)
- 设置响应状态码为
206,并写入Content-Range、Accept-Ranges、Content-Length等关键响应头 - 使用
InputStream跳过起始位置(skip()或FileChannel.position()),再分块写入OutputStream
2. 关键响应头必须正确设置
客户端(如浏览器、下载工具)依赖这些头判断是否支持续传:
-
Accept-Ranges: bytes—— 表明服务端支持字节范围请求 -
Content-Range: bytes 0-1023/10000—— 当前返回的字节范围及文件总大小 -
Content-Length—— 当前响应体长度(不是整个文件) -
Content-Type和Content-Disposition保持不变,确保下载行为正常
3. 大文件需避免内存加载,用 NIO 或 BufferedStream 流式传输
千万不能用 FileUtils.readFileToByteArray() 或 Resource.getInputStream().readAllBytes(),否则 OOM。
- 推荐使用
FileChannel配合ByteBuffer进行零拷贝或高效分段读取 - 或使用
BufferedInputStream+skip()定位,再循环read()写出 - 每次读写控制在 8KB–64KB,平衡性能与内存占用
- 务必在 finally 中关闭流,或使用 try-with-resources
4. 注意边界与兼容性细节
实际开发中容易出错的地方:
- 多个 Range(如
bytes=0-100,200-300)一般可忽略,只处理单个 Range(主流客户端也只发一个) - Range 超出文件长度时,应返回
416 Requested Range Not Satisfiable,并带Content-Range: */{fileLength} - Spring Boot 2.6+ 的
ResourceHttpRequestHandler默认支持 Range,但仅限静态资源;动态接口仍需手动实现 - 反向代理(如 Nginx)可能吞掉 Range 头或缓存全量响应,需配置
proxy_cache_disable $http_range;等规则











