最简路径是复用配置超时和transport的全局http.client,检查statuscode和关闭resp.body,用context控制请求生命周期,按业务域隔离client。

用 net/http 发起 GET/POST 请求最简路径
Go 标准库的 net/http 足够轻量且可靠,不需要引入第三方 HTTP 客户端(比如 resty)也能完成绝大多数 REST API 调用。关键在于别直接用 http.Get 或 http.Post ——它们不支持超时、无法复用连接、没法设 Header,一上线就容易出问题。
正确做法是构造一个带配置的 http.Client:
client := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 30 * time.Second,
},
}-
Timeout必设,否则请求卡住会拖垮整个服务 -
Transport配置决定连接复用能力,高并发下没它,dial tcp: too many open files很快出现 - 别在每次请求都
new(http.Client),它本身是线程安全的,全局复用即可
处理 JSON 响应时如何避免 panic 和空指针
用 json.Unmarshal 解析响应体前,必须检查 resp.Body 是否为 nil,且 resp.StatusCode 是否在 2xx 范围。很多客户端代码只判 err != nil,但 HTTP 错误码(如 401、500)不会触发 err,只会返回非空 resp + 错误 body。
典型错误写法:json.Unmarshal(resp.Body, &v) —— resp.Body 是 io.ReadCloser,不能重复读,且没关会导致连接泄漏。
立即学习“go语言免费学习笔记(深入)”;
- 始终用
defer resp.Body.Close()(在检查resp不为nil后) - 先读取
body, _ := io.ReadAll(resp.Body),再传给json.Unmarshal(body, &v) - 对非 2xx 状态码,建议单独解析错误结构体(如
{"error":"invalid_token"}),而不是直接 panic
带认证和动态 Header 的请求怎么组织更可控
Token 类认证(Bearer、API Key)不该硬编码在每个请求里。推荐封装一个带上下文的请求函数,把认证逻辑收口:
func DoRequest(ctx context.Context, method, url string, body io.Reader, headers map[string]string) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
return nil, err
}
for k, v := range headers {
req.Header.Set(k, v)
}
return client.Do(req)
}- 用
context.WithTimeout控制单次请求生命周期,比Client.Timeout更灵活(比如某些接口允许 30s,其他只要 2s) -
headers用map传入,方便动态加Authorization、X-Request-ID、Content-Type - 如果 Token 从外部获取(如 JWT),不要在函数内调用刷新逻辑——那属于业务层职责,客户端只负责“拿已知 token 发请求”
为什么 http.Client 不该全局变量乱传
很多人把 *http.Client 当成工具类塞进各种 struct,甚至作为参数层层传递。这会导致两个实际问题:一是测试时无法 mock(标准库 client 没接口抽象);二是不同业务共用同一 Transport,某个接口频繁失败可能拖慢其他请求(比如长连接被异常服务器占满)。
- 按业务域隔离 client:支付调用用一个,用户服务调用用另一个,各自配独立
Transport - 真要 mock 测试,用
http.ServeMux起个本地 test server,或用httptest.NewServer,比试图替换 client 更可靠 - 如果用了依赖注入框架(如
fx),client 应作为 singleton 提供,但需明确标注用途,比如PaymentHTTPClient
真正难的不是发请求,而是让错误可观察、连接可管理、行为可测试。Header 写错、JSON 字段名大小写不一致、Body 没 close、超时时间设成 0 —— 这些细节在压测或网络抖动时才暴露。









