http.get不能上生产,因其调用http.defaultclient且timeout为0、无连接复用、不处理重定向,易致goroutine永久阻塞;应显式构造带超时和transport配置的*http.client并全局复用。

别用 http.Get 上生产,它没超时、不复用连接、不处理重定向,一压就挂。
为什么 http.Get 不能直接上生产
它本质调的是 http.DefaultClient,而这个 client 的 Timeout 是 0(无限等待),Transport 也没限制连接池大小。DNS 卡住、后端响应慢、TCP 握手失败都会让 goroutine 永久阻塞。
- 只适合本地调试,比如
http.Get("http://localhost:8080/health") - 线上调第三方 API 时,常见错误是忽略
resp.Body.Close(),导致连接池耗尽,报错如net/http: request canceled (Client.Timeout exceeded while awaiting headers) - 即使只读
resp.StatusCode,也得关 body——否则未读数据会锁死 TCP 连接
怎么构造安全可用的 *http.Client
必须显式 new 一个,并设 Timeout 和 Transport,且全局复用。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
-
Timeout控制整个请求生命周期(DNS + 连接 + 写 + 读),建议设为 5–10 秒 -
MaxIdleConnsPerHost默认是 2,高并发下会排队;设成 100 更合理,但别盲目调高,容易打满服务端或触发本地 fd 限制 - 别碰
DisableKeepAlives,除非你真想放弃连接复用 - 示例:
client := &http.Client{ Timeout: 5 * time.Second, Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 30 * time.Second, }, }
POST JSON 时 Content-Type 和 body 怎么配
服务端按 Content-Type 解码,类型不匹配就收不到数据。
- 必须手动调
req.Header.Set("Content-Type", "application/json"),http.Post不支持设 header - body 要用
bytes.NewBuffer(data)包json.Marshal输出的字节切片,别用strings.NewReader(string(data))——多一次 string 转换,触发额外内存分配 -
json.Marshal可能返回 error(比如字段没加json:"xxx"tag 或含不可序列化类型),不检查就 panic - 正确写法:
data, _ := json.Marshal(req) req, _ := http.NewRequest("POST", url, bytes.NewBuffer(data)) req.Header.Set("Content-Type", "application/json")
resp.Body.Close() 必须怎么写才不出错
漏关不是内存泄漏,是连接池被占满,后续请求卡死或直接失败。
- 必须在
if err != nil检查之后、读 body 之前写defer resp.Body.Close() - 哪怕只读
resp.StatusCode,也要关;哪怕用io.Copy(io.Discard, resp.Body)丢弃 body,也要关 - 别在
if resp.StatusCode != 200就提前 return——body 没关,连接就永远回不去连接池 - 大响应体才考虑流式读取;小响应(几十 KB)直接
io.ReadAll(resp.Body)更稳妥
真正难的不是“怎么发”,而是超时控制、连接复用、header 设置、body 关闭这四点全部对齐——少一个,流量一上来就出问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










