Spring Boot用StreamingResponseBody实现大文件流式下载,核心是边读边写、即产即传,避免OOM;需返回ResponseEntity<StreamingResponseBody>,设置响应头,安全读取文件并支持ZIP动态打包、断点续传与限速。

Spring Boot 用 StreamingResponseBody 实现大文件流式下载,核心是绕过内存全量加载,让数据边读边写、即产即传。它不把文件塞进 byte[],而是交由框架管理输出流,由你定义“怎么一帧一帧写出去”。对百MB甚至GB级文件,这是避免 OOM 和提升并发能力的标配方案。
关键配置与基础写法
必须确保 Controller 方法返回 ResponseEntity<StreamingResponseBody>,不能直接 void 或 byte[]。Spring MVC 会自动识别该类型并异步执行写入逻辑:
- 设置响应头:Content-Type 固定为
APPLICATION_OCTET_STREAM,Content-Disposition 指定附件名(注意中文需 URLEncoder 编码) - StreamingResponseBody 是函数式接口,实现
writeTo(OutputStream out)即可——所有读文件、压缩、加解密等操作都在这个回调里完成 - 务必使用 try-with-resources 或显式 close 输入流(如 FileInputStream、ZipInputStream),否则连接可能卡住或资源泄漏
安全读取本地文件的典型结构
避免路径穿越漏洞,先做路径白名单校验再构建 File:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Paths.get(safeBaseDir).resolve(userInput).normalize()得到标准化路径 - 检查该路径是否仍属于 safeBaseDir 目录树内(
startsWith(safeBaseDir.toAbsolutePath().normalize())) - 确认文件存在且是普通文件(
Files.isRegularFile(path)),再打开 FileInputStream
配合 ZIP 动态打包下载
适合导出多个小文件或生成临时压缩包的场景:
- 在 writeTo 回调中创建
ZipOutputStream包裹 response.getOutputStream() - 逐个打开待打包文件,用
ZipEntry添加条目,再通过缓冲区(如 8KB byte[])循环 copy 内容 - 每个文件写完调用
zipOut.closeEntry(),全部写完调用zipOut.finish() - 无需提前生成物理 ZIP 文件,全程内存占用稳定在几 MB 级别
支持断点续传与限速的扩展点
StreamingResponseBody 本身不内置这些能力,但可在 writeTo 中灵活注入逻辑:
- 断点续传:解析请求头中的
Range,跳过指定字节再开始读写;同时返回206 Partial Content和Content-Range头 - 限速:在每次 write 后统计已发字节数和耗时,用
Thread.sleep()控制节奏(例如每秒不超过 1MB) - 进度监听/日志:在循环写入过程中记录已传输百分比,可用于后台审计或调试

















