go中http header处理需注意三点:写对位置、用对方法、避开自动管理字段;set覆盖写入,add追加写入;host等字段须改对应结构体字段而非header;读取应使用get而非直接map访问;响应头必须在write或writeheader前设置。

Go 里处理 HTTP Header 不是“设了就行”,关键在三点:写对位置、用对方法、避开自动管理字段。直接上手就能用,但错一步就静默失效。
req.Header.Set() 和 req.Header.Add() 的区别必须分清
Set 是覆盖写入,Add 是追加写入——这直接影响服务端是否收到你想要的值。
req.Header.Set("Content-Type", "application/json")req.Header.Set("Authorization", "Bearer abc123")req.Header.Add("Cookie", "sid=abc; Path=/")req.Header.Add("Cookie", "theme=dark; Path=/")
如果用 Set 写两次 <code>Cookie,后一次会把前一次完全顶掉;而 Add 才能保留两个独立的 Set-Cookie 字段(响应头同理)。服务端对 Cookie 头的解析依赖多个原始值,不是逗号拼接的单字符串。
哪些 Header 字段不能手动 Set
Go 标准库会接管部分字段,手动设置会被忽略,甚至触发错误。
-
Host:应改req.Host字段,而非req.Header.Set("Host", ...) -
Content-Length:由底层自动计算并写入,设了也无效 -
Connection、Transfer-Encoding:HTTP/1.1 协议层控制字段,强行设置可能断连 -
User-Agent、Accept等则完全可写,无限制
现象:代码里写了 req.Header.Set("Host", "api.example.com"),抓包发现仍是默认 Host;换成 req.Host = "api.example.com" 才生效。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
读取请求头时别直接访问 map
用 r.Header["X-Request-ID"] 看似方便,但不安全——它绕过键名规范化逻辑,大小写敏感且不兼容 Go 内部存储格式。
- ✅ 正确:
r.Header.Get("X-Request-ID")、r.Header.Get("x-request-id")都能拿到值 - ⚠️ 危险:
r.Header["X-Request-ID"]在某些情况下返回空 slice,尤其当客户端用小写传头时 - ⚠️ 更危险:
r.Header["content-type"]可能 panic(nil slice),而Get永远返回 string(空或值)
Header 键在内部统一转为 X-Request-Id 这类首字母大写格式,Get() 自动做归一化匹配;直接 map 访问不触发该逻辑。
响应头设置时机比内容还关键
一旦调用 w.Write() 或 w.WriteHeader(),再往 w.Header() 里塞东西就彻底丢弃,且不报错。
- ✅ 正确顺序:
w.Header().Set("Cache-Control", "no-cache")→w.WriteHeader(200)→w.Write(...) - ⚠️ 常见翻车:
json.NewEncoder(w).Encode(data)会自动调用WriteHeader(200),所以 header 必须在这之前设好 - ⚠️ 中间件陷阱:若某个中间件提前写了 body(比如日志记录器用了
httputil.DumpResponse),后续 handler 就再也设不了 header
最隐蔽的问题是:没报错、没 warning,header 就是不发出去——得靠抓包或检查 resp.Header 才能发现。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










