http客户端请求失败时err为nil但状态码异常,需手动检查resp.statuscode并校验;应显式创建自定义http.client避免defaultclient全局污染;错误包装要保留url等上下文;json解析前须验证content-type;需按状态码语义区分可恢复与不可恢复错误。
HTTP客户端请求失败时,err 为 nil 但响应状态码异常怎么办
Go 的 http.Client.Do 只在网络层或协议解析出错时返回非 nil 的 err;而 HTTP 状态码如 404、500 会被正常返回,err 仍是 nil。这是最常被忽略的“假成功”场景。
- 必须手动检查
resp.StatusCode,不能只依赖err != nil - 推荐在调用
resp.Body.Close()前判断状态码,避免资源泄漏 - 对业务关键接口,建议封装统一校验逻辑,例如:
if resp.StatusCode < 200 || resp.StatusCode >= 300 { return fmt.Errorf("HTTP %d: %s", resp.StatusCode, resp.Status) }
使用 http.DefaultClient 导致连接复用失效或超时失控
http.DefaultClient 是全局单例,直接修改其 Timeout 或 Transport 会影响所有包(包括第三方库),极易引发隐蔽的并发问题或超时策略冲突。
- 始终显式构造自定义
*http.Client,哪怕只是复制默认配置:client := &http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 30 * time.Second, }, } - 不要复用同一个
http.Client实例处理差异极大的请求(如短查询 vs 长轮询),应按场景分组管理 - 注意
http.Transport中的MaxConnsPerHost默认为 0(不限制),高并发下可能耗尽文件描述符
错误链中丢失原始 HTTP 错误上下文
用 fmt.Errorf("failed to fetch user: %w", err) 包装错误时,若 err 来自 net/http(如 net/url.Error 或 net.OpError),原始 URL、method、host 等信息会丢失,排查困难。