go可通过os.openfile、io.seek和http range请求实现断点续传,关键在于同步服务端偏移量、避免覆盖写错位置;需校验206响应及content-range头、用seek精确写入、持久化.offset文件防丢失,并实测服务端range支持。

Go 本身不提供开箱即用的「断点续传」抽象,但用 os.OpenFile、io.Seek 和 HTTP Range 请求组合,就能可靠实现——关键不在“有没有”,而在“怎么同步服务端偏移量”和“怎么避免覆盖写错位置”。
HTTP 客户端如何发 Range 请求并校验响应
服务端必须支持 206 Partial Content,且返回 Content-Range 头;客户端不能只看状态码,还要解析该 header 判断起始偏移是否匹配预期。
- 用
http.NewRequest手动设置Rangeheader:"bytes=1024-"表示从第 1024 字节开始到末尾 - 收到响应后,检查
resp.StatusCode == http.StatusPartialContent,再读resp.Header.Get("Content-Range"),例如"bytes 1024-9999/10000",提取出1024校验是否等于本地已写入长度 - 若不匹配(比如服务端文件被替换),应清空临时文件并重新下载,否则续传会错位
本地文件如何安全追加写入且保留已下载部分
不能用 os.O_APPEND:它依赖内核维护文件偏移,而断点续传需要精确控制写入位置;必须用 os.O_WRONLY | os.O_CREATE 打开,再用 file.Seek 定位。
- 打开文件时加
os.O_SYNC或后续调用file.Sync(),防止系统缓存导致断电丢数据 - 写入前先
file.Seek(offset, io.SeekStart),确保写入起点准确;offset来自上一次成功写入的字节数,或从服务端Content-Range解析得到 - 写完一批数据后,立即用
atomic.StoreInt64(&written, newOffset)更新内存中的已写长度,避免多 goroutine 竞态
如何持久化断点位置并防重复写入
断点信息不能只存在内存里——进程崩溃就丢了;也不能直接写进目标文件头部,会污染原始数据。推荐独立存储一个 .resume 文件。
- 为
example.zip创建同名example.zip.resume,内容为纯文本:offset=12345\nurl=https://... - 每次写入数据前,先更新
.resume文件(用ioutil.WriteFile全量覆盖,避免部分写失败) - 启动续传时,优先读
.resume,验证其中url是否与当前任务一致(防止用户换链接但没删 resume 文件) - 下载完成后,务必显式删除
.resume文件,否则下次可能误判为未完成
最易被忽略的是服务端行为一致性:有些 CDN 或 Nginx 配置会忽略 Range 请求、返回 200 而非 206,或者对小文件禁用分片——这些都会让客户端以为续传成功,实际却重写了开头。上线前一定要用 curl -v -r 1024- https://... 实测响应头。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











