最安全、内存最友好的流式下载方式是用http.get配合io.copy;因io.copy内置32kb缓冲区、自动处理eof和错误,避免手动read的边界问题与oom风险,且必须先校验statuscode再close body。

直接用 http.Get + io.Copy 是最安全、内存最友好的流式下载方式;别碰 ioutil.ReadAll 或 bytes.Buffer.Write,大文件会立刻吃光内存。
为什么 http.Get 后不能直接读 resp.Body.Read?
手动调用 resp.Body.Read 容易漏掉错误边界:没处理好缓冲区大小时,要么反复小块读导致性能差,要么一次分配过大切片引发 OOM。更关键的是,你得自己循环直到 io.EOF,而忘记某次 Read 返回 0 但 err == nil 就可能提前退出,文件写半截。
io.Copy 内部已封装完整逻辑:它用固定大小(默认 32KB)缓冲区分块读写,自动处理 EOF、临时网络中断重试(仅限底层连接层)、以及各种 io.Reader 实现的兼容性。你只需确保 dst 是可写的 *os.File,src 是未关闭的 resp.Body。
- 必须在
io.Copy前检查resp.StatusCode,否则 404/500 页面也会被写进文件 -
defer resp.Body.Close()要放在状态码检查之后,避免成功前就关掉 body - 目标文件要用
os.O_CREATE | os.O_WRONLY | os.O_TRUNC打开,否则可能因权限或只读 flag 导致写入失败
带 User-Agent 和认证头时怎么构造请求?
http.Get 不支持自定义 header,硬塞会报错或被忽略。必须换用 http.Client + http.NewRequest 组合。
常见错误是直接赋值 req.Header = map[string][]string{...} —— 这会绕过 Go 的 header 安全校验(比如禁止设置 Host),导致请求被服务端静默拒绝或返回 400。
- 用
req.Header.Set("User-Agent", "Mozilla/5.0"),不是req.Header["User-Agent"] = []string{...} - GitHub raw 链接必须加
Accept: application/octet-stream,否则返回 HTML 页面而非二进制流 - 若只需单次请求,新建
&http.Client{Timeout: 30 * time.Second},别动http.DefaultClient,避免影响其他模块
大文件下载时 CPU 占用高,是不是 io.Copy 有问题?
不是 io.Copy 的问题,它本身几乎不消耗 CPU。高 CPU 通常来自你在流式写入过程中高频触发的操作:
- 每 KB 就调用一次
log.Printf或更新进度条(尤其用fmt.Printf("\r...")配合终端刷新) - 在
io.Copy外层包了一层自定义io.Reader,但每次Read都做复杂计算或锁操作 - 目标磁盘是 NFS 或低速 USB 设备,系统调用阻塞时间长,Go runtime 频繁调度协程抢资源
真正要优化的是监控粒度:把进度回调从“每字节”拉宽到“每 1MB”,或改用 runtime.ReadMemStats 做异步采样,而不是卡在数据流里。
断点续传的 Range 请求为什么总被忽略?
服务端是否支持断点续传,不由你发不发 Range 决定,而取决于它是否在 HEAD 响应头里声明 Accept-Ranges: bytes。很多静态托管(Vercel、Netlify、GitHub Pages)默认关掉这个头,你发了 Range,它照样返回 200 + 全量内容,而不是 206 Partial Content。
- 务必先发一次
HEAD请求,检查resp.Header.Get("Accept-Ranges") == "bytes" -
Range值必须严格等于本地文件当前长度:fmt.Sprintf("bytes=%d-", fileInfo.Size()),错一位就会续传错位 - 收到 206 后,用
os.OpenFile(..., os.O_WRONLY|os.O_APPEND)打开文件,别用os.Create,否则覆盖已有内容
最常被忽略的一点:即使服务端支持 Accept-Ranges,某些 CDN 会在响应头里加 Cache-Control: no-store 或 Vary: *,导致中间代理拒绝缓存,进而让 Range 请求失效——这种问题只能靠抓包确认响应头,没法靠代码绕过。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











