go 语言设置 http 请求头必须在调用 client.do() 前用 req.header.set() 或 add(),且仅对新建可写请求有效;set() 覆盖同名字段,add() 追加;host 需通过 req.host 设置;client 无 header 字段,须每次请求前手动设。

Go 语言里设置 HTTP 请求头,核心就一条:用 req.Header.Set() 或 req.Header.Add(),但必须在调用 http.DefaultClient.Do() 之前做——晚了就无效。
为什么 req.Header.Set() 不生效?
最常见的情况是:你构造了 http.Request,但没注意它默认是只读的(尤其用 http.NewRequest() 创建后,Header 是可写的;但如果你用 http.NewRequestWithContext() 或从中间件/测试中拿到的请求对象,Header 可能已被冻结)。
- 确认请求对象是自己新建的,不是从 handler 或 mock 中“传入”的只读副本
- 检查是否在
client.Do(req)之后才调用Set()—— 这时候连接可能已发出,Header 修改被忽略 - 某些代理或重定向逻辑会重建请求,原始 Header 设置丢失,需用
client.CheckRedirect手动补全
Set() 和 Add() 的区别在哪?
Set() 会覆盖同名 Header 字段,Add() 是追加(对支持多值的 Header 如 Cookie 有意义)。
- 设
Content-Type、Authorization这类单值字段,用req.Header.Set("Content-Type", "application/json") - 设多个
Cookie,用req.Header.Add("Cookie", "a=1")和req.Header.Add("Cookie", "b=2"),否则后者会覆盖前者 - 注意:
Host字段不能用Set()直接改,得通过req.Host = "example.com"或构造时指定url的 host 部分
自定义 client 时 Header 设置容易漏掉什么?
用 http.Client 自定义超时或 Transport 时,Header 不是 client 的属性,而是每个 *http.Request 的属性——所以没法“全局设一次”,必须每次请求前手动设。
- 别写
client := &http.Client{...}; client.Header.Set(...)——http.Client根本没有Header字段 - 想复用逻辑?封装成函数,比如
func newRequest(url string, body io.Reader) (*http.Request, error),里面统一设 Header - 如果用
context控制生命周期,确保 Header 设置在http.NewRequestWithContext()返回后、Do()调用前完成
Header 设置本身很简单,难的是时机和上下文——它不报错,只是默默失效。调试时打印 req.Header 看一眼,比猜半天快得多。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











