直接 ctx.SendFile 不适合大文件,因其默认全量读入内存导致OOM;需手动解析Range头、返回206状态码并流式传输,或用http.ServeContent自动支持分片。

为什么直接 ctx.SendFile 不适合大文件
因为 Iris 的 ctx.SendFile 或 ctx.ServeFile 默认会把整个文件读入内存再吐给客户端,遇到几百 MB 以上的文件,Node.js 进程内存飙升、响应变慢甚至 OOM。这不是 Iris 的 bug,而是它默认走的是「全量同步读取 + 全量响应」路径,没启用流式传输和 Range 支持。
必须手动处理 Range 请求头才能分片
Iris 不像 Express 那样自动识别并响应 Range 头,也不内置 206 Partial Content 逻辑。你得自己解析 ctx.Request().Header.Get("Range"),校验格式(如 bytes=0-1023),计算 offset/length,再用 os.Open + io.CopyN 或 http.ServeContent 流式返回对应片段。
- 错误写法:
ctx.SendFile("big.zip")—— 没有 Range 支持,永远 200,无法分片 - 正确思路:先
stat获取文件大小 → 解析Range→ 设置Content-Range和Content-Length→ 用io.Copy从文件 offset 开始读取指定字节数 - 别漏掉状态码:合法 Range 返回
ctx.StatusCode(206);非法 Range(如超出文件大小)要返回416 Requested Range Not Satisfiable并带Content-Range: bytes */
用 http.ServeContent 是最稳的流式方案
Iris 底层是 net/http,所以可以直接复用标准库的 http.ServeContent,它原生支持 Range、If-Modified-Since、ETag 等,且自动处理边界条件(比如请求末尾超出文件长度时自动截断)。你只需要提供一个 http.File 实现或包装 os.File。
示例关键片段:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
file, _ := os.Open("large.mp4")
defer file.Close()
fi, _ := file.Stat()
ctx.ResponseWriter().Header().Set("Accept-Ranges", "bytes")
http.ServeContent(ctx.ResponseWriter(), ctx.Request(), "large.mp4", fi.ModTime(), &fileReader{file})
其中 fileReader 是个自定义 struct,实现 http.File 接口的 Read、Seek、Stat 方法——重点是 Seek 要能跳转到 Range 指定位置,Read 只读所需字节。
前端发起分片请求时注意 responseType 和合并顺序
即使后端支持 Range,前端 JS 用 fetch 下载分片时也容易出错:
- 必须设
responseType: 'arraybuffer',否则二进制数据会被转成字符串损坏 - 每个分片的
Range起始偏移要对齐(比如 0–999999、1000000–1999999),不能重叠或留空洞 - 合并 ArrayBuffer 不能简单拼接,要用
Uint8Array+set()按 offset 写入目标 buffer - 最后生成 Blob 时,MIME 类型要和原始文件一致(如
video/mp4),否则双击打不开
真正难的不是单个分片流式返回,而是前后端对齐 Range 解析逻辑、错误重试策略、以及多线程下载时的磁盘 I/O 竞争——这些在高并发下容易暴露,但 Iris 本身不帮你管。










