c.SendFile()返回404或空内容的根本原因是Fiber仅允许从当前工作目录及其子目录读取文件,不支持绝对路径穿透、符号链接跳转或路径遍历(如../),且未校验文件存在性与读取权限。

直接用 c.SendFile() 就能下载服务器本地文件,但路径错误、权限缺失或 MIME 类型不匹配会导致 404、空响应或浏览器直接打开而非下载。
为什么 c.SendFile() 返回 404 或空内容
根本原因不是文件不存在,而是 Fiber 默认只允许从当前工作目录(go run 所在路径)及其子目录中读取——它不支持绝对路径穿透或符号链接跳转,且不会自动处理路径遍历(如 ../)。
- 确保传给
c.SendFile()的路径是相对路径(如"./uploads/report.pdf"),或用filepath.Abs()显式转成绝对路径再校验是否存在 - Fiber 不会帮你创建父目录,如果
./uploads/不存在,c.SendFile()会静默失败(返回 200 + 空 body),建议先os.Stat()检查 - Windows 下路径分隔符不用手动替换,
filepath.Join("uploads", "file.txt")安全可靠
如何强制浏览器下载而非打开文件
c.SendFile() 默认根据扩展名设置 Content-Type,但不会设 Content-Disposition: attachment。要触发下载行为,必须手动设置响应头。
- 先调用
c.Set("Content-Disposition", "attachment; filename=\""+filename+"\""),其中filename需做 URL 编码(尤其含中文或空格) - 再调用
c.SendFile(path);顺序不能反,否则头可能被覆盖 - 若想复用原文件名,可从路径提取:
filepath.Base(path),但注意过滤掉非法字符(如/、..)
大文件下载卡顿或内存暴涨
c.SendFile() 内部使用 io.Copy 流式传输,本身不加载全文到内存,但若路径指向一个正在被写入的文件(如日志),或文件系统缓存不足,会出现阻塞或超时。
- 对 >100MB 的文件,建议加超时控制:用
c.Context().SetDeadline(time.Now().Add(5 * time.Minute)) - 避免在 handler 中对同一文件高频并发调用
SendFile,底层os.Open可能触发文件系统锁争用 - 生产环境推荐用
c.File()(v3 新增)替代SendFile,它支持范围请求(Rangeheader)、自动 ETag 和条件 GET,更适合静态资源分发
最容易被忽略的是:Fiber 的 SendFile 不校验文件是否可读(os.ReadMode),也不做 MIME 类型协商——你得自己确保 Web 用户运行 Go 进程的 UID 有读取该文件的权限,且别依赖浏览器“猜”类型来决定是否下载。











