spring boot 3 中 gridfstemplate 不支持断点续传,因其无字节偏移接口,仅能返回完整文件流;必须使用 gridfsbucket.opendownloadstream() 并手动解析 range 头提取 start/end 参数,配合正确设置 content-range 响应头与 206 状态码,才能实现可靠分片读取。

Spring Boot 3 默认不支持 GridFS 断点续传,必须手动解析 Range 请求头并调用 GridFSBucket.openDownloadStream() 的 start/end 参数 —— 其他方式(如 skip/limit、自定义 query、改集合名)都会破坏文件结构或返回错误数据。
为什么不能用 GridFsTemplate 实现断点续传
GridFsTemplate 没有暴露字节偏移接口,它的 getResource() 和 findOne() 只能返回完整文件流;即使你手动拼 InputStream 并跳过前 N 字节,也会丢失 chunk 校验、无法处理末尾截断、且在并发上传导致 n 字段不连续时直接读错块。官方驱动明确要求:随机读取必须走 GridFSBucket.openDownloadStream()。
-
GridFsTemplate适合「全量上传/下载/元数据管理」,不适合分片读取 - 试图用
Query+skip(10)模拟 offset,实际跳的是 10 个fs.chunks文档,不是 10 字节 - 即使你给
GridFsTemplate指定了 bucket 名(如"tempFs"),它仍无法控制起始位置
如何正确解析 Range 头并转为 start/end
HTTP Range 头格式为 bytes=1000-1999 或 bytes=1000-,需在 Controller 层手动提取,不能依赖 Spring 自动绑定。关键逻辑是:提取 start,判断是否有 end,再结合文件总长度做边界修正。
- 用
request.getHeader("Range")获取原始字符串,正则匹配数字(例如Pattern.compile("bytes=(\d+)-(\d*)")) -
start必须 ≥ 0;若end为空(如bytes=1000-),end参数应省略(传null),否则驱动会读到文件末尾 - 若
end有值但 > 文件总长度,应设为fileLength,避免驱动抛IllegalArgumentException - 响应中必须写
response.setHeader("Content-Range", "bytes " + start + "-" + (end-1) + "/" + fileLength) - 状态码必须是
206 Partial Content,否则浏览器拒绝续传
GridFSBucket 必须显式配置 bucket 名才能隔离存储
Spring Boot 3 的自动配置只创建默认 fs bucket,如果你要区分「临时上传中」和「已发布」文件,不能靠 spring.data.mongodb.grid-fs-database 配置项切换 —— 它对 GridFSBucket 无效。真正起作用的是构造时传入的 bucket 名字符串。
- 在
@Configuration类中声明两个@Bean,分别命名:@Bean(name = "tempBucket")和@Bean(name = "prodBucket") - 每个 bean 构造时调用
GridFSBuckets.create(database, "tempFs"),bucket 名就是fs.files集合的前缀(如tempFs.files) - 注入时用
@Resource(name = "tempBucket"),不能只用@Autowired GridFSBucket,否则类型冲突 - 上传时也得用对应 bucket 的
openUploadStreamWithId(),否则openDownloadStream()查不到文件
chunkSize 不一致会导致 openDownloadStream 定位失败
openDownloadStream() 内部依赖 fs.files.chunkSize值计算 chunk 边界。如果上传时用了非默认 chunkSizeBytes(比如 128KB),但后续下载时驱动读到的 chunkSize 是默认 255KB,就会跨块读取、解包失败、返回乱码。
- 上传必须用
GridFSBucket.uploadFromStream()或openUploadStream(),并显式指定chunkSizeBytes - 不要混用
GridFsTemplate(无 chunkSize 控制)和GridFSBucket(有)操作同一 bucket - 检查
fs.files中目标文件文档的chunkSize字段是否与预期一致(可用 Robo 3T 或 mongosh 查询) - 前端请求
Range: bytes=0-1048575(1MB)时,后端传给openDownloadStream()的start=0,end=1048576,驱动会自动按 chunkSize 拆解读取
最容易被忽略的是:上传和下载必须使用同一套 bucket + 同一 chunkSize + 同一 GridFSBucket 实例,三者缺一不可。哪怕只是上传用了 GridFsTemplate,下载用 GridFSBucket,都可能因元数据字段缺失或 chunkSize 写入不一致而定位失败。











