fiber 不支持多文件直接打包下载,需用 io.pipe + zip.writer 流式生成 zip 并响应,设置正确 content-type 和 content-disposition 头,避免内存堆积与路径穿越,确保 zw.close() 完成后再结束响应。

直接用 fiber.Ctx 原生不支持多文件打包下载,必须手动压缩并流式响应。Fiber 没有类似 Express 的 res.download() 批量封装,也没有内置 ZIP 流式生成器;你得自己构造 ZIP 文件头、写入文件内容、设置正确响应头,并确保不阻塞主线程或耗尽内存。
为什么不能直接用 c.SendFile() 或 c.Attachment()
这两个方法只接受单个文件路径或字节切片:c.SendFile("a.pdf") 只能发一个;传入多个路径会 panic;传入 ZIP 字节数组则需全部加载进内存——对 100 个 10MB 文件就是 1GB 内存占用,不可行。
-
c.Attachment()仅设置Content-Disposition头,不处理压缩逻辑 - ZIP 包必须实时生成(用
archive/zip+io.Pipe),否则高并发下易 OOM - Fiber 的
c.Response().BodyWriter()是底层fasthttp的 writer,可复用但不自动 flush,需手动控制写入节奏
正确做法:用 io.Pipe + zip.Writer 流式生成并响应
核心是避免内存堆积:开一个 goroutine 往 pipe 写 ZIP 数据,主线程把 pipe reader 直接交给 c.Response().WriteBody() —— 这样 ZIP 边压边传,内存峰值恒定在几 KB。
- 必须设响应头:
c.Set("Content-Type", "application/zip")和c.Set("Content-Disposition", `attachment; filename="files.zip"`) - ZIP 文件名不能含中文或特殊字符,否则浏览器可能乱码;建议用
url.PathEscape("files.zip")安全编码 - 每个
zip.FileHeader的Name字段要规范路径(如"docs/report.pdf"),避免"../etc/passwd"路径穿越 - 调用
zw.Close()前务必defer zw.Flush(),否则末尾 ZIP 元数据丢失,解压报“invalid zip file”
常见错误:文件名乱码、解压失败、连接超时
这些基本都源于 ZIP header 或 HTTP 头配置不对:
- 中文文件名解压后显示乱码?
zip.FileHeader要设NonUTF8: false并确保 Go 源文件是 UTF-8 编码(默认即满足) - 下载的 ZIP 打不开?漏了
zw.Close(),或c.Response().WriteBody()在 ZIP 写完前就返回 - 大文件下载中途断连?没设
c.Context().SetConnectionClose(),导致 fasthttp 复用连接但客户端提前关闭 - 并发下载卡死?在 pipe writer goroutine 里用了
time.Sleep或阻塞 IO,应改用context.WithTimeout控制总耗时
最易被忽略的是:ZIP 流必须完整写入才能结束响应,而 Fiber 不会自动等待 goroutine;你得用 sync.WaitGroup 或 chan struct{} 确保 zw.Close() 完成后再让 handler 返回。否则 handler 提前退出,连接被关,客户端收到截断的 ZIP。











