c.SendFile 默认以inline模式返回导致浏览器直接渲染而非下载;需手动设置Content-Disposition为attachment并校验路径防遍历,其底层天然支持断点续传但依赖文件ModTime和正确响应头。

c.SendFile 是最直接的文件下载方式,但它默认以 inline 模式返回,浏览器可能直接渲染而非下载;真要触发“另存为”,必须手动设置 Content-Disposition 响应头。
用 c.SendFile 下载但浏览器不弹保存框?
这是默认行为:Fiber 调用 http.ServeFile 时设的是 Content-Disposition: inline,图片、PDF、TXT 等类型会被浏览器尝试打开。要强制下载,得覆盖响应头:
- 先调
c.Set("Content-Disposition", "attachment; filename=\""+filename+"\""),注意 filename 必须是 ASCII 或 URL 编码(中文需url.PathEscape) - 再调
c.SendFile(filepath),路径必须是服务端真实可读的绝对或相对路径 - 别在
SendFile后再写其他响应,它内部会调c.Status(200).Send()并结束流程
想支持断点续传或大文件流式下载?
c.SendFile 底层用 http.ServeContent,天然支持 Range 请求和 304 Not Modified,但前提是请求带 If-None-Match 或 If-Modified-Since,且文件有确定的 ModTime。你不需要额外写逻辑,只要确保:
- 文件系统保留了原始修改时间(比如用
os.Chtimes改过时间,就可能破坏 ETag 计算) - 不手动覆盖
Last-Modified或ETag响应头,除非你完全接管校验逻辑 - 避免对同一文件频繁调
os.Create再写入——这会重置ModTime,导致缓存失效
用户传路径参数下载文件,怎么防目录遍历?
直接拼接 ./uploads/" + c.Params("file") 是高危操作,../../../etc/passwd 会逃逸。正确做法是:
- 用
filepath.Join拼路径,再用filepath.EvalSymlinks和strings.HasPrefix校验是否仍在白名单根目录内 - 示例:
abs, _ := filepath.Abs(filepath.Join("./uploads", c.Params("file"))),然后检查strings.HasPrefix(abs, "/full/path/to/uploads/") - 拒绝任何含
..、开头为/、或匹配.*(如.env、.git)的文件名 - 别依赖
filepath.Clean单独过滤——它不能阻止符号链接绕过
真正难的不是调哪个函数,而是路径校验那几行代码漏掉一个条件,就可能让整个 uploads 目录被拖走。别图省事跳过 EvalSymlinks,也别把用户输入当可信字符串直接塞进 os.Open。











