http下载必须手动设超时并检查statuscode,否则易卡死或写入错误内容;需配置user-agent、accept头防403,禁用自动重定向以控制cookie传递,大文件须用io.copy流式落盘,并严格按顺序关闭resp.body和文件句柄。

HTTP 下载必须手动设超时和检查 StatusCode
直接用 http.Get 会卡死或下错文件——它没超时、不校验状态码、不处理重定向上下文。比如网络抖动时永久 hang,或服务端返回 404/502 却照样写入空文件。
- 用
&http.Client{Timeout: 30 * time.Second}替代http.DefaultClient -
resp, err := client.Do(req)后立刻检查resp.StatusCode:只接受200;302需自己判断是否带 Cookie 重放 -
defer resp.Body.Close()必须在 StatusCode 检查之后,否则 4xx/5xx 的 body 关不掉,连接复用会出问题
下载前不加 User-Agent 和 Accept 头大概率 403
GitHub raw、Cloudflare、Vercel 等默认拦截无头请求。返回 403 不是权限问题,是服务端压根没认出你是客户端。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 必须设
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") - 下载 ZIP/PDF/PNG 等二进制文件时,加
req.Header.Set("Accept", "application/octet-stream"),否则可能返回 HTML 登录页 - 若目标需登录态(如私有仓库 PGN),还得配
http.CookieJar,并禁用自动重定向:CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }
大文件下载必须用 io.Copy 流式落盘
用 ioutil.ReadFile 或 io.ReadAll 读整个响应体,几百 MB 就 OOM;resp.Body.Read 手动管理缓冲区又容易丢数据或越界。
- 始终用
io.Copy(dstFile, resp.Body),内部用 32KB 缓冲区,安全省心 - 创建本地文件时用
os.O_CREATE | os.O_WRONLY | os.O_TRUNC,避免权限或覆盖失败 - 下载中途出错(如网络断开),
io.Copy返回非 nil error,此时文件已存在但不完整——得自己删掉再重试
中文文件名必须用 filename*=UTF-8'' 编码
直接写 attachment; filename="订单.xlsx",Chrome/Firefox 会乱码或截断;url.PathEscape 也不对,那是给 URL 路径用的。
- 用
url.PathEscape编码文件名后拼到filename*=UTF-8''后面,例如:attachment; filename*=UTF-8''%E8%AE%A2%E5%8D%95.xlsx -
Content-Type推荐设为application/octet-stream,避免 MIME 类型探测干扰 - 别漏掉
w.Header().Set("Content-Disposition", ...),否则浏览器可能 inline 打开而非下载
实际跑通的关键点不在“怎么写”,而在“哪里关”:resp.Body.Close() 在状态码检查后、io.Copy 前;file.Close() 在 io.Copy 后、函数返回前;client.Close()(SFTP/FTP)或 conn.Quit()(FTP)不能漏——漏了 fd 会耗尽。
这些 close 顺序和时机,比逻辑本身更容易出 silent bug。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










