最简下载路径是http.Get后检查StatusCode、关闭resp.Body、用io.Copy写入文件;需定制请求头时用http.Client+http.NewRequest;大文件须流式处理避免内存溢出;证书错误仅测试时可跳过验证。

用 http.Get 下载文件最简可行路径
直接调用 http.Get 获取响应体,再写入本地文件是最常用方式。注意它不自动重定向(除非显式启用),也不处理 4xx/5xx 状态码——出错时仍会返回非 nil 的 *http.Response,但 resp.Body 可能含错误信息。
- 务必检查
resp.StatusCode,比如if resp.StatusCode != http.StatusOK就该提前返回 -
resp.Body必须关闭,否则连接不释放,容易触发too many open files - 用
io.Copy而非手动循环读取,避免内存膨胀(尤其大文件)
resp, err := http.Get("https://example.com/data.zip")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, resp.Status)
}
out, err := os.Create("data.zip")
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
需要带请求头或 Cookie 怎么办
用 http.Client + http.NewRequest 手动构造请求,比 http.Get 灵活得多。常见需求如设置 User-Agent、携带认证 token、绕过某些反爬逻辑,都靠这个组合。
-
http.DefaultClient是全局默认客户端,修改它的Timeout或Transport会影响所有默认请求 - 若只需单次定制,建议新建
&http.Client{},避免副作用 - Header 需用
req.Header.Set(),不能直接赋值req.Header = map[string][]string{...}(会丢掉底层安全校验)
client := &http.Client{Timeout: 30 * time.Second}
req, _ := http.NewRequest("GET", "https://api.example.com/file.pdf", nil)
req.Header.Set("User-Agent", "MyApp/1.0")
req.Header.Set("Authorization", "Bearer xxx")
resp, err := client.Do(req)
// 后续同上:检查状态码、关闭 Body、io.Copy...
大文件下载如何避免内存爆掉
Go 默认不会把整个响应体加载进内存,但如果你误用 ioutil.ReadAll(resp.Body) 或 bytes.Buffer.Write,就等于把整个文件读进 RAM。正确做法是流式处理——io.Copy 内部就是分块读写的,只要确保目标文件以 os.O_CREATE | os.O_WRONLY | os.O_TRUNC 打开即可。
- 不要用
os.OpenFile(..., os.O_APPEND)写下载文件,否则可能在断点续传之外的场景下写乱数据 - 如果需断点续传,得手动加
Rangeheader,并用os.OpenFile(..., os.O_WRONLY|os.O_APPEND)接续写入 - 监控进度?用
io.TeeReader包一层,每次读完回调更新计数器
HTTPS 证书校验失败怎么临时绕过(仅测试)
生产环境绝不该跳过证书验证,但内网测试或自签名服务调试时,可能遇到 x509: certificate signed by unknown authority。此时需自定义 http.Transport 并替换其 TLSClientConfig。
立即学习“go语言免费学习笔记(深入)”;
- 必须只在明确的开发/测试配置下启用,上线前删掉或注释掉相关代码
- 不要用空 struct{} 或
nil赋值给TLSClientConfig,要显式 new 一个并设InsecureSkipVerify: true - 即使跳过证书验证,仍需检查 HTTP 状态码和响应完整性(比如 Content-Length 是否匹配)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
实际项目里最容易被忽略的是错误路径下的 resp.Body.Close() ——很多示例只在成功分支里关,但无论 StatusCode 是多少、err 是否为 nil,只要 resp 不为 nil,Body 就必须关。










