如何使用Golang获取HTTP请求头_Golang net/http Header处理示例

12次阅读

应使用 req.Header.Get(“Key”) 安全读取请求头,它忽略大小写、返回空字符串而非 panic,并自动合并多值;需原始多值时用 req.Header[“Key”] 并先判空;cookie 等特殊字段不存于 Header 映射中,须用 r.Cookies() 或 r.Header”Cookie”。

如何使用Golang获取HTTP请求头_Golang net/http Header处理示例

如何从 *http.Request 中安全读取请求头字段

gonet/http 包中,请求头以 http.Header 类型存在,本质是 map[String][]string。直接用 req.Header["User-Agent"] 可能 panic(如果 key 不存在且你忘了判空),更推荐用 req.Header.Get("User-Agent") —— 它返回 "" 而非 panic,且自动合并同名多值(如多个 Cookie 头会以逗号分隔)。

  • Get() 忽略大小写,req.Header.Get("accept-encoding")req.Header.Get("Accept-Encoding") 效果一致
  • 若需原始多值(例如解析多个 Set-Cookie),用 req.Header["Set-Cookie"],但务必先检查 key 是否存在:if vals, ok := req.Header["X-forwarded-For"]; ok { ... }
  • 注意:客户端可能发送重复 header(如两个 Authorization),Get() 只返回第一个值;需要全部时必须用 map 访问

如何在中间件中修改或添加响应头

修改响应头必须在 WriteHeader() 或首次调用 Write() 之前完成,否则会被忽略。常见错误是想在 handler 结束后“补”一个 X-Response-Time,结果无效。

func loggingMiddleware(next http.Handler) http.Handler {     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {         start := time.Now()         // ✅ 此处可安全写入 Header         w.Header().Set("X-Process", "go-server")         w.Header().Add("X-Frame-Options", "DENY")          // 注意:不能在这里调用 w.WriteHeader() 或 w.Write() 前就 return          next.ServeHTTP(w, r)          // ⚠️ 此处再调用 w.Header().Set(...) 已无效果         log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))     }) }
  • Set() 覆盖已有值,Add() 追加新值(适用于允许重复的 header,如 Warning
  • 若需删除某个 header,用 w.Header().Del("X-Deprecated")
  • 所有 header 修改对下游中间件可见,但不可逆(无法“撤回”已 Add() 的值)

为什么 r.Header.Get("Cookie") 返回空,但 r.Cookies() 能拿到?

因为 Cookie 是 HTTP/1.1 特殊处理的 header:标准库在解析请求时,会将原始 Cookie: a=1; b=2 拆解并缓存为 []*http.Cookie,但**不会写回 r.Header 映射中**。所以 r.Header.Get("Cookie") 总是空字符串。

  • 要读取 cookie 值,优先用 r.Cookies()(返回所有)或 r.Cookie("session_id")(按名查找)
  • 若需原始 Cookie 字符串(比如透传给下游服务),应改用 r.Header["Cookie"](注意是 slice,取 [0])或更稳妥地:遍历 r.Header 找 key 等于 "Cookie"(忽略大小写)的项
  • 同理,Content-LengthHost 等字段也可能被标准库提取并用于内部逻辑,不一定完整保留在 r.Header

如何正确处理大小写敏感的自定义 header

虽然 http.Header 内部用规范化的 key(首字母大写,如 "X-Request-Id")存储,但 Go 允许你用任意大小写访问 —— 底层通过 textproto.CanonicalMIMEHeaderKey 转换。不过,如果你依赖外部系统(如 nginx、Envoy)注入的 header 名为 x-request-id,它仍能被 req.Header.Get("X-Request-Id") 正确匹配。

立即学习go语言免费学习笔记(深入)”;

  • 不建议手动调用 textproto.CanonicalMIMEHeaderKey,除非你在实现底层协议解析
  • 若需严格区分大小写(极少见),应直接操作 req.Header map 并遍历 key,但违背 HTTP 规范,多数代理会重写 header 名
  • 生产环境建议统一使用标准格式命名自定义 header:以 X- 开头,单词驼峰(X-Trace-Id),避免下划线或全小写

实际开发中最容易忽略的是 header 修改时机和 Cookie 字段的特殊性 —— 一个在响应写出前漏掉 Set-Cookie,一个因误用 Get("Cookie") 导致鉴权失败,都是高频线上问题。

text=ZqhQzanResources