必须用http.setcookie(w, cookie)而非手动拼接set-cookie头,因其自动处理url编码、max-age整数格式、多cookie分头及rfc兼容性;r.cookie需显式区分http.errnocookie与其它错误;删除cookie须镜像原始path/domain/secure/samesite参数。

http.SetCookie 和 r.Cookie 是核心,框架只是封装——别被中间件绕晕,先搞清底层行为。
为什么不能直接 w.Header().Set("Set-Cookie", ...)
手动拼接 Set-Cookie 头会出三类问题:
• cookie.Value 里的空格、中文、=、; 不做 URL 编码,浏览器静默丢弃
• Max-Age 写成字符串或单位错(比如写 "3600" 而非整数 3600),Chrome/Firefox 直接忽略该 Cookie
• 多个 Cookie 时用分号连在一起,但 RFC 6265 要求每个 Set-Cookie 是独立响应头,手拼会合并成一个无效头
必须用 http.SetCookie(w, cookie):它自动处理编码、时间序列化、头拆分和 RFC 兼容格式。
r.Cookie("name") 的 err 判断不能只写 if err != nil
常见错误是这样写:
cookie, err := r.Cookie("session_id")
if err != nil {
http.Error(w, "未登录", http.StatusUnauthorized)
return
}
这会导致两种情况混为一谈:
• err == http.ErrNoCookie:客户端根本没发这个 Cookie(首次访问、已清除、路径不匹配)→ 应跳登录页
• err != nil && err != http.ErrNoCookie:Cookie 值损坏、超长、Base64 解码失败等真异常 → 应记日志 + 500
正确做法是显式判断:
cookie, err := r.Cookie("session_id")
if err != nil {
if err == http.ErrNoCookie {
http.Error(w, "未登录", http.StatusUnauthorized)
return
}
log.Printf("解析 session_id Cookie 失败: %v", err)
http.Error(w, "服务异常", http.StatusInternalServerError)
return
}
删除 Cookie 必须完全复刻原始设置参数
只设 MaxAge: 0 不够。浏览器按 Name + Path + Domain + Secure + SameSite 五元组匹配旧 Cookie 才覆盖。漏掉任何一个,新 Cookie 就不会生效。
- 当初设置时用了
Path: "/admin",删的时候也得写Path: "/admin";写成"/"就删不掉 - 开发时用
localhost,千万别设Domain;设了Domain: "localhost"浏览器会拒绝存储 - 如果原 Cookie 是
Secure: true(HTTPS 下发),删的时候也必须设Secure: true,否则 HTTP 页面能删,HTTPS 页面删不掉 - 推荐删除写法:
MaxAge: 0(立即过期) +Value: ""+ 所有原始字段镜像复制
HttpOnly、Secure、SameSite 不是“可选配置”,是上线前必验开关
这三个字段一旦漏配,安全风险立刻落地:
• HttpOnly: false → XSS 漏洞下,document.cookie 一行 JS 就能盗走 session_id
• Secure: false(生产环境)→ HTTP 流量明文传输 token,中间人劫持无压力
• SameSite: http.SameSiteDefaultMode 或未设 → Chrome 91+ 默认按 Lax 处理,但老浏览器/其他 UA 可能放开 CSRF 攻击面
建议上线前加检查:
cookie := &http.Cookie{
Name: "session_id",
Value: id,
Path: "/",
MaxAge: 3600,
HttpOnly: true,
Secure: isProd, // 环境变量控制
SameSite: http.SameSiteLaxMode,
}
本地开发用 http://localhost 时 Secure 可关,但代码里必须通过配置开关控制,不能硬写 false。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











