可靠,但必须配合 http.StatusPartialContent 和正确设置 Content-Range 响应头,否则客户端会当完整响应处理,续传失败;需校验 Range 格式、处理边界情况并动态校准文件长度。

Go 中用 http.Request.Header.Get("Range") 提取范围请求是否可靠?
可靠,但必须配合 http.StatusPartialContent 和正确设置 Content-Range 响应头,否则客户端会当完整响应处理,续传失败。
常见错误是只读了 Range 头,却返回 200 OK 或漏写 Content-Range。浏览器或 wget 一看没 Content-Range,就清空已下载部分重来。
-
Range格式通常为"bytes=1024-2047",也可能出现"bytes=1024-"(从某偏移到末尾)或无效值,需校验 - 用
strings.TrimPrefix剥离"bytes="后,再用strings.Split拆分"-",避免直接strconv.ParseIntpanic - 注意:
Range超出文件大小时,应返回416 Range Not Satisfiable,并设Content-Range: bytes */<var>fileSize</var>
Go 文件下载服务如何支持断点续传?
核心不是“实现续传”,而是“按 Range 返回对应字节段 + 正确响应码和头”。Go 标准库本身不自动处理,得自己解析、裁剪、响应。
关键路径是:打开文件 → 获取 os.Stat → 解析 Range → 计算起始/结束偏移 → io.CopyN 或 io.Copy 配合 io.LimitReader 流式输出。
立即学习“go语言免费学习笔记(深入)”;
- 别用
os.ReadFile全读进内存,大文件直接 OOM;要用os.Open+file.Seek - 响应状态码必须是
http.StatusPartialContent (206),不是200 -
Content-Length应设为本次返回的字节数(非整个文件),Content-Range格式为"bytes <var>start</var>-<var>end</var>/<var>total</var>" - 记得设
Content-Type(如"application/octet-stream"),否则某些客户端可能拒绝续传
为什么用 io.CopyN 比 io.Copy 更适合 Range 场景?
因为 io.CopyN 明确限制拷贝字节数,天然适配 Range 的长度计算结果;而 io.Copy 会一直读到源 EOF,容易越界。
比如请求 bytes=1000-1999(共 1000 字节),你 Seek 到 1000 后,用 io.CopyN(w, r, 1000) 就能精准吐出这 1000 字节,不会多也不会少。
- 若用
io.Copy,必须包装一个带长度限制的io.Reader,比如io.LimitReader(file, n),反而多一层封装 -
io.CopyN返回实际拷贝数,可用于校验是否读到预期长度(例如文件末尾不足时) - 注意:如果
start已超过文件大小,file.Seek会成功但后续读不到数据,io.CopyN返回 0 —— 这时应返回416
Go 中处理 Range 请求时最容易被忽略的边界情况
不是语法或函数调用问题,而是 HTTP 协议语义和文件系统行为的交叉点。
-
Range: bytes=0-是合法的,表示“从开头到结尾”,但很多代码只处理"-"在中间的情况,漏掉这种写法 - 文件大小为 0 时,
Range: bytes=0-0应返回206+ 空响应体,而不是416;但bytes=1-才是416 - 多个 Range(如
bytes=0-100,200-300)属于 multipart/byteranges,标准下载工具极少用,可暂不支持,但要明确返回416而不是静默降级 - Linux 下文件可能被 truncate,
os.Stat获取的 size 和实际Seek时的长度不一致 —— 每次读前建议再Stat一次或用file.Seek(0, io.SeekEnd)动态获取当前长度
断点续传真正卡住的地方,往往不是怎么写,而是没想清楚“客户端发来的 Range 到底意味着什么”和“我返回的响应头到底告诉了它什么”。










