应使用 c.Request.Header.Get 读取原始请求头,它大小写不敏感、返回 string、不存在时为空字符串;c.GetHeader 仅为薄封装,行为完全一致,但易引发误解;需获取全部同名 header 值时应直接访问 c.Request.Header["X-Custom"] 得到 []string 切片。

用 c.Request.Header.Get 读原始请求头,不是 c.GetHeader
直接调用 c.Request.Header.Get("X-Forwarded-For") 是最稳妥的方式。它大小写不敏感、返回 string、不存在时为空字符串,且完全基于 Go 标准库行为,稳定可靠。c.GetHeader 虽然存在,但只是对前者的薄封装,名字容易让人误以为 Gin 有额外逻辑——其实没有。别被名字带偏。
多个同名 header 怎么取全?别用 Get,改用 c.Request.Header["X-Custom"]
c.Request.Header.Get 只返回第一个值,遇到像 X-Forwarded-For 这种可能被多层代理追加的字段,会丢掉中间跳数。真要拿全部值,得直接访问 map:
-
c.Request.Header["X-Forwarded-For"]返回[]string,按顺序包含所有出现的值 - 注意 key 是规范化后的(首字母大写),比如原始 header 是
x-forwarded-for,map 里 key 是X-Forwarded-For - 切片可能为空,需判空;取最后一个元素才是最外层代理看到的客户端 IP
代理 behind Nginx 时,c.ClientIP() 为什么不准?没设信任列表
c.ClientIP() 默认只信任 localhost,一旦前面挂了 Nginx,它就会把 Nginx 的 IP 当成客户端 IP。必须显式设置可信代理:
-
r.SetTrustedProxies([]string{"192.168.1.10"})—— 填 Nginx 所在机器的真实 IP - 若部署在 Kubernetes 或 Docker 网络里,可能是一段 CIDR,如
"10.0.0.0/8" - 千万别留空或设为
nil,否则默认信任所有 IP,有伪造风险 - 设置后,
c.ClientIP()才会去解析X-Forwarded-For或X-Real-IP,并验证来源是否可信
透传 header 到下游服务时,Director 函数里别漏重写 Host
反向代理场景下,仅靠 proxy.Director = func(r *http.Request) { ... } 不够。常见错误是只改了 r.URL.Host,却忘了同步更新 r.Host:
-
r.URL.Host控制请求发往哪个地址 -
r.Host决定 HTTP 请求行里的Host:字段,很多后端服务靠它做虚拟主机路由 - 两者不一致会导致 404 或 SSL SNI 错误
- 正确写法:
r.Host = url.Host(和r.URL.Host保持一致)
http.Request,Gin 没做任何增强——这意味着你不能指望它自动合并、解码或标准化多个同名字段,每一步都得自己判断要不要、怎么处理。


















