go 的 http.client 需通过自定义 roundtripper 包装 transport 实现请求日志,注意 body 重放、敏感信息脱敏、dumprequestout/dumpresponse 性能开销及 context 控制开关。

Go 的 http.Client 本身不记录请求日志,得自己加中间层
Go 标准库的 http.Client 默认静默执行,连 curl -v 那种基础输出都没有。想看到请求方法、URL、Header、响应状态、耗时,必须手动注入日志逻辑——不是改 Client 配置,而是包装 RoundTrip 方法。
常见错误是试图用 log.Println 直接打在 http.HandlerFunc 里,那只能拦服务端接收的请求,对出站 HTTP 调用完全无效。出站日志必须从客户端侧切入。
- 最轻量做法:写一个自定义
RoundTripper,包裹默认的http.Transport - 别直接修改全局
http.DefaultClient,尤其在多 goroutine 场景下容易污染其他模块 - 注意日志内容是否含敏感字段(如
Authorization、Cookie),生产环境建议默认脱敏
用 httputil.DumpRequestOut 和 DumpResponse 打印原始字节流
这两个函数能生成接近 curl -v 的文本格式,但要注意它们会读取并消耗 request body 和 response body 的 io.ReadCloser,导致后续逻辑拿不到数据。
典型翻车现场:httputil.DumpRequestOut(req, true) 后,下游 handler 拿到空 body;或者没重放 body,json.NewDecoder(resp.Body) 解析失败。
- 必须用
req.Body = io.NopCloser(bytes.NewReader(bodyBytes))把 body “还回去” -
DumpResponse的第二个参数控制是否 dump body,设为false可避免大文件阻塞和内存暴涨 - 别在高并发场景无节制调用
Dump*,它们内部做深拷贝,有明显性能开销
bodyBytes, _ := io.ReadAll(req.Body)
req.Body = io.NopCloser(bytes.NewReader(bodyBytes))
dump, _ := httputil.DumpRequestOut(req, false) // false 表示不 dump body
log.Printf("[OUT] %s", string(dump))
用 context.Context 控制单次请求是否开启日志
全量日志在生产环境不可行,但调试某个特定调用链又需要临时打开。硬编码开关或配置项太僵硬,推荐用 context.WithValue 透传日志开关。
比如你调用支付网关失败,只想看那一笔请求的完整 trace,而不是所有 HTTP 出流量都刷屏。
- 定义 key:
type ctxLogKey string; const logEnabledKey ctxLogKey = "enable_http_log" - 发起请求前:
ctx = context.WithValue(ctx, logEnabledKey, true) - 自定义
RoundTripper中检查ctx.Value(logEnabledKey)再决定是否 dump - 避免用
string做 context key,否则易冲突;也不要用int或struct{}空类型,可读性差
第三方库如 go-resty/resty 的日志开关只是表象
resty 的 SetDebug(true) 确实能打印请求/响应,但它底层仍是封装了 httputil.Dump* + body 重放逻辑。问题没消失,只是被包起来了。
你依然会遇到:body 被读两次、JSON 解析失败、大文件 OOM、日志中混入二进制乱码(比如没指定 charset 的 text/plain 响应)。
- 启用前确认响应 Content-Type 是否可安全转字符串,否则加
SetDumpBodyLimit(1024)限制长度 - 它默认不脱敏 Header,
Authorization会明文打出,上线前务必检查 - 它的 Debug 日志走
log.Printf,无法对接 zap/zapcore 等结构化日志器,需自行替换SetLogger
真正难的不是打出日志,而是让日志既可读又不干扰业务流,还能按需开关、自动脱敏、不拖慢性能。这些细节堆起来,比写个 fmt.Printf 多十倍工作量。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











