iris.Context.ServeFile 默认不触发下载,而是以text/plain渲染;强制下载需用SendFile并设置Content-Disposition头,注意文件名编码、路径校验及兼容性处理。

iris.Context.ServeFile 会直接触发浏览器下载吗
不会,ServeFile 默认以 Content-Type: text/plain 返回文件内容,浏览器通常直接渲染(比如显示文本、JSON 或 HTML),而不是弹出下载对话框。要强制下载,必须显式设置 Content-Disposition 响应头。
如何用 iris.Context 发起强制文件下载
核心是两步:设置响应头 + 调用 ServeFile 或 SendFile。推荐用 SendFile,它比 ServeFile 更底层、更可控,且默认不自动猜测 MIME 类型,避免干扰下载行为。
- 先调用
ctx.ResponseWriter().Header().Set("Content-Disposition", "attachment; filename=\"xxx.txt\""),注意 filename 必须用英文双引号包裹,中文名需 URL 编码(如filename=\"%E6%97%A5%E5%BF%97.txt\") - 再调用
ctx.SendFile("/path/to/file.txt", nil),第二个参数传nil表示不启用范围请求(Range)和缓存控制;若需支持大文件断点续传,可传入&iris.SendFileOptions{EnableRange: true} - 确保文件路径是服务端真实可读的绝对路径或相对于可执行文件的相对路径;
SendFile不会自动查找./public等目录,路径必须精确
常见错误:404 或下载后文件损坏
多数问题出在路径和权限上:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
-
SendFile传入的路径不存在或不可读 → 返回 404;建议用os.Stat提前校验:if _, err := os.Stat(filepath); os.IsNotExist(err) { ctx.StatusCode(404); return } - 使用
ServeFile时没设Content-Disposition→ 浏览器打开而非下载;更隐蔽的是,某些浏览器(如 Chrome)对 .json/.txt 文件即使设了 header 仍可能内联显示,此时改用SendFile更可靠 - 文件名含空格或中文但未编码 →
Content-Disposition解析失败,导致 header 被忽略;务必用url.PathEscape处理文件名,不要用QueryEscape - 并发下载大文件时内存暴涨 →
SendFile默认流式传输,一般不占大量内存;但如果误用ctx.JSON或ctx.WriteString先读全文件再返回,就会 OOM
带参数的动态文件下载(如 /download?id=123)
不能直接把用户输入拼进文件路径,必须做白名单校验或路径规范化限制:
- 用
filepath.Clean消除../跳转:cleanPath := filepath.Clean("/data/" + id),再检查是否仍在允许目录内:if !strings.HasPrefix(cleanPath, "/data/") { ctx.StatusCode(403); return } - 更安全的做法是用 ID 查数据库或映射表获取真实路径,完全避开路径拼接;例如:
realPath := fileMap[id],其中fileMap是预加载的合法 ID→路径映射 - 下载前建议记录日志:
log.Printf("download request: id=%s, path=%s, ip=%s", id, realPath, ctx.RemoteAddr()),便于审计异常行为
实际中容易被忽略的是 Content-Disposition 的 filename 字段兼容性——老版 IE 不支持,所以必须同时提供标准 filename 和 filename,但 Iris 的 SendFile 不自动处理这个细节,得手动写全:ctx.Header("Content-Disposition", "attachment; filename=\""+escName+"\"; filename*=UTF-8''"+url.PathEscape(origName))。


















