Golang流式ZIP压缩下载无需临时文件,通过archive/zip写入http.ResponseWriter,设置Content-Type和Content-Disposition头,校验路径白名单与文件权限,启用Deflate压缩,控制超时与内存。

用 Golang 实现文件压缩下载,核心是服务端动态打包多个文件(或单个大文件)为 ZIP,并通过 HTTP 流式响应直接传输给客户端,避免生成临时 ZIP 文件、节省磁盘 I/O,同时显著减少网络传输量。
使用 archive/zip + http.ResponseWriter 流式压缩
不落地存储 ZIP,而是将压缩流直接写入 HTTP 响应体。关键点:设置正确的 Content-Type 和 Content-Disposition 头,用 zip.NewWriter 包装 responseWriter,逐个添加文件(支持目录遍历或指定路径)。
- 设置响应头:
w.Header().Set("Content-Type", "application/zip")和w.Header().Set("Content-Disposition", `attachment; filename="download.zip"`) - 用
zip.NewWriter(w)创建压缩写入器,调用zw.Create()添加文件头,再用io.Copy()写入原始文件内容 - 压缩完必须调用
zw.Close(),它会刷新并写入 ZIP 结束标记,否则客户端解压失败
压缩前校验文件权限与存在性,避免 500 错误
用户请求的文件路径不能直接信任。需做白名单检查(如限定在 /data/uploads/ 下)、跳过符号链接、拒绝访问系统敏感路径,并对每个待打包文件执行 os.Stat 验证可读性。
- 用
filepath.Clean()规范路径,再判断是否在允许根目录内(例如strings.HasPrefix(cleanPath, allowRoot)) - 对每个文件调用
os.Open()前先os.Stat(),若返回os.IsNotExist或权限错误,跳过或记录日志,不中断整个压缩流程 - 可选:限制总文件数和总大小(如超过 100 个或 500MB 则拒绝),防止 DoS 攻击
支持单文件压缩(减小传输体积)与多文件批量打包
即使只下载一个大文件(如 200MB 日志),ZIP 压缩也能明显降低传输量(尤其文本类)。Golang 的 zip.Writer 默认不启用压缩,需显式传入 zip.FileHeader 并设置 Method: zip.Deflate。
立即学习“go语言免费学习笔记(深入)”;
- 创建文件头时:
header, _ := zip.FileInfoHeader(info),然后设header.Method = zip.Deflate - 对小文件(如 header.Method = zip.Store(仅归档,不压缩),省去压缩开销
- 多文件场景下,注意 ZIP 中路径不要含盘符或绝对路径(如
/home/u/file.txt),应转为相对路径(如logs/error.log),避免解压污染客户机根目录
处理大文件时控制内存与超时,避免阻塞 goroutine
流式压缩本身不加载全部文件进内存,但若并发高或单文件极大(如数 GB),仍需防止单次响应耗时过长或内存抖动。
- 在 HTTP handler 中设置上下文超时:
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Minute),并在读取源文件时用io.CopyN或带 ctx 的io.Copy(配合自定义 reader) - 用
bufio.NewReaderSize(f, 64*1024)提升读取效率,避免频繁小块 syscall - 若后端存储是对象存储(如 S3),可结合
io.SectionReader分块拉取,而非一次性GetObject










