会。http.Get 默认将整个响应体读入内存,大文件易导致OOM;正确做法是流式下载到磁盘,配合Range请求实现断点续传,并用io.Copy安全分块写入。

用 http.Get 直接读大文件会 OOM 吗?
会。默认 http.Get 把整个响应体读进内存(resp.Body.Read 不调用的话,底层连接可能卡住;一调用 io.ReadAll 就崩)。1GB 文件触发 GC 压力,还可能直接被系统 kill。
正确做法是边下载边写入磁盘,不缓存全文:
- 用
os.OpenFile以os.O_CREATE | os.O_WRONLY | os.O_APPEND模式打开文件(断点续传时关键) - 用
io.CopyN或分块io.Copy(比如每次make([]byte, 32*1024))流式写入 - 务必检查
resp.StatusCode,不是200或206就别往下写了
怎么发 Range 请求实现断点续传?
核心是设置请求头 Range: bytes=1024-,告诉服务端只返回从第 1024 字节开始的剩余内容。服务端必须支持 Accept-Ranges: bytes,否则返回 200 而非 206,续传就错。
实操要点:
立即学习“go语言免费学习笔记(深入)”;
大小仅1兆左右 ,足够轻便的商城系统; 易部署,上传空间即可用,安全,稳定; 容易操作,登陆后台就可设置装饰网站; 并且使用异步技术处理网站数据,表现更具美感。 前台呈现页面,兼容主流浏览器,DIV+CSS页面设计; 如果您有一定的网页设计基础,还可以进行简易的样式修改,二次开发, 发布新样式,调整网站结构,只需修改css目录中的css.css文件即可。 商城网站完全独立,网站源码随时可供您下载
- 先
os.Stat获取已下载文件大小,作为start - 构造 header:
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start)) - 检查响应状态码:必须是
206,否则说明服务端不支持或范围越界 - 响应头里要含
Content-Range,例如bytes 1024-1023999/1024000,可据此校验完整性
io.Copy 和手动 Read/Write 哪个更适合大文件?
io.Copy 更稳——它内部已做 32KB 缓冲、错误重试和长度截断处理,比手写 for { n, _ := src.Read(buf); dst.Write(buf[:n]) } 少踩三个坑:未处理 io.EOF、忽略 n == 0 边界、没检查 Write 返回的 n 是否等于 Read 的 n。
但要注意:
- 不要用
io.Copy直接拷贝到bytes.Buffer或strings.Builder——又回内存了 - 如果需实时计算 hash 或限速,用
io.TeeReader或包装src,别改写逻辑 - 超长下载建议加 context:用
http.NewRequestWithContext(ctx, ...),避免卡死无法 cancel
如何判断断点续传是否真正生效?
不能只看文件大小追加了,得验证三件事:
- 发起请求前,
HEAD该 URL,确认响应头有Accept-Ranges: bytes且Content-Length匹配总大小 - 断点请求后,响应状态码是
206,且Content-Range中的 total 值与HEAD得到的一致 - 下载完成后,用
sha256.Sum256对本地文件全量哈希,和服务端提供的ETag或文档声明值比对
少验证任意一项,都可能遇到“看起来续上了,其实中间某段是旧缓存或 416 错误响应”。









