r.cookie("name")返回nil是正常现象,主因是浏览器未发送cookie:请求头缺失、path/domain不匹配、secure设错、samesite拦截或值含未解码字符。

r.Cookie() 返回 nil 和 http.ErrNoCookie 是正常现象,不是 bug;真正的问题往往出在请求头缺失、路径不匹配或值未解码——别急着改逻辑,先查浏览器是否真发了 Cookie。
为什么 r.Cookie("name") 总是返回 nil
这不是解析失败,而是浏览器根本没把 Cookie 带过来。常见原因有:
- 请求压根没带
Cookie请求头(比如新用户、清空过缓存、跨站请求被 SameSite 拦截) - 服务端设的
Path是/admin,但请求地址是/api/user,浏览器按 RFC 规则自动过滤 -
Domain设成了example.com,但当前访问的是localhost:8080—— 浏览器拒绝匹配(localhost不支持Domain属性) - Cookie 值含
%3D或%20等 URL 编码字符,但你直接用了cookie.Value比较,而 Go 不自动解码,得手动调url.QueryUnescape(cookie.Value)
http.SetCookie() 设置后浏览器没保存?
最常见误操作:用 req.AddCookie() 替代 http.SetCookie()。前者只影响当前请求对象内部的 Cookies() 列表,完全不会生成 Set-Cookie 响应头。
- 正确写法:
http.SetCookie(w, &http.Cookie{Name: "token", Value: "abc", Path: "/", HttpOnly: true, Secure: true}) -
Secure: true在 HTTP 环境下会静默失效(浏览器丢弃),本地调试可临时设false,但上线前必须改回true -
MaxAge: 0表示“立即删除”,不是“不设过期”;要设会话级 Cookie,请留空MaxAge和Expires - Value 中含逗号、分号、空格时,必须先用
url.PathEscape()(不是QueryEscape)编码,否则浏览器可能截断
读取多个同名 Cookie 或处理非法格式
r.Cookies() 返回的是切片,但它只解析合法 RFC 6265 格式的条目。遇到非法格式(如值里有未转义的分号、等号前后有空格),整个 Cookie 头会被跳过,不报错也不提示。
- 浏览器发送的原始头可能是:
Cookie: a=1; b=2; user=name with space→ 最后一项因空格非法,整条头被忽略 - 同名 Cookie(如两次
Set-Cookie: theme=light)按规范后出现的覆盖前一个,r.Cookies()只返回最后一个 - 若需兼容旧客户端或自定义格式,别依赖
r.Cookies(),改用r.Header.Get("Cookie")手动拆解 +strings.Split(),再逐段http.ParseCookie()
签名 Cookie 必须分离值与签名,且验证失败绝不降级
标准库不提供加密,gorilla/securecookie 是主流选择,但自己实现也常见。关键陷阱在于:
- 签名格式必须是
value.base64-signature,不能拼成value|signature或其他分隔符——base64 后缀天然无歧义 - 验证失败时,返回空值或默认值;**绝不能**返回原始
value字段(攻击者删掉签名就能绕过校验) - 不要用
hmac.Sum([]byte(value + secret)),这易受长度扩展攻击;必须用h := hmac.New(...); h.Write([]byte(value)); h.Sum(nil) -
gorilla/securecookie要求密钥长度严格匹配算法(如 AES-256 需 32 字节),少一字节都会 panic
SameSite 和 Secure 的组合行为在不同浏览器版本间仍有差异,尤其是 iOS Safari 对 SameSite=Lax 的重定向处理。别只测 Chrome,真机抓包看请求头是否发出,比任何日志都可靠。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











