go断点续传需服务端支持http range协议、客户端正确处理偏移写入;服务端可用http.servecontent自动处理,客户端需head获取总长、seek定位后writeat写入,务必校验206状态码与offset。

Go 文件上传/下载如何支持断点续传
Go 本身标准库不提供开箱即用的断点续传能力,必须手动实现 HTTP Range 协议交互 + 本地文件偏移写入。核心在于:服务端要支持 Range 请求头,客户端要能读取已下载部分长度、跳过已写内容、追加写入。
HTTP 客户端怎么发带 Range 的请求
直接在 http.Request 中设置 Range 头即可,但注意格式必须严格为 bytes=start-end(end 可省略表示“到结尾”),且服务端返回状态码必须是 206 Partial Content,不是 200。
常见错误现象:416 Requested Range Not Satisfiable —— 说明服务端不支持 Range,或你传的范围超出了文件总大小(需先 HEAD 获取 Content-Length)。
- 先用
HEAD请求拿到目标文件总大小(resp.Header.Get("Content-Length")) - 检查本地已有文件长度:
fi, _ := os.Stat(localPath); offset := fi.Size() - 构造 Range 值:
fmt.Sprintf("bytes=%d-", offset)(从 offset 开始到末尾) - 务必检查响应状态码是否为
206,否则不能继续;若返回200,说明服务端忽略 Range,需换逻辑或换服务端
os.File 怎么从指定位置开始写入而不覆盖
关键不是用 os.WriteFile,而是打开文件时用 os.O_WRONLY | os.O_CREATE,再调用 file.Seek(offset, io.SeekStart) 定位,最后用 file.Write() 或 io.Copy() 写入。否则默认从开头写,会把已有内容全冲掉。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
容易踩的坑:os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644) 默认光标在开头;不 Seek 就写,等于重写整个文件。
- 打开文件必须带
os.O_APPEND吗?不用,Append会强制光标移到末尾,无法控制偏移;应去掉它,手动Seek - 写入前一定要校验
Seek返回值是否等于期望 offset,避免因文件被截断导致错位 - 建议用
file.WriteAt(data, offset)更安全,它不依赖当前光标位置
服务端怎么让 Go HTTP 服务支持 Range
标准 http.ServeFile 和 http.FileServer 默认就支持 Range,但仅限静态文件;如果走自定义 handler,就得自己解析 Range 头、计算 byte range、设置 Content-Range 响应头、返回 206 状态码。
性能影响:大文件分片响应时,别用 bytes.Buffer 全部加载进内存,要用 io.CopyN 或 io.ReadFull 分段读磁盘并写 response body。
- 用
http.ServeContent是最稳妥的方式:它自动处理 Range、If-Modified-Since、ETag 等,只需提供ContentLength、ModTime和一个func(w io.Writer, r io.Reader) error - 别手动拼
Content-Range字符串,易出格式错误(如漏空格、单位错写成byte) - 如果文件可能被并发修改,
ModTime和Content-Length要在每次请求时重新 stat,不能缓存
断点续传真正难的不是 Go 代码怎么写,而是服务端和客户端对 Range 行为的理解是否一致——比如某些 CDN 或反向代理会吞掉 Range 头,或者把 206 强转成 200;实际部署前,务必用 curl -v -H "Range: bytes=100-" URL 手动验证响应头和状态码。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










