echo 中 cookie 操作必须用 c.cookie() 和 c.setcookie(),禁用手动 http.setcookie;session 必须通过 session.middleware() 注册并指定存储后端,注意密钥长度、域名配置及 cookie 与 session 过期时间协同。

Cookie 读写必须用 c.Cookie() 和 c.SetCookie()
Echo 不直接暴露 http.Request.Cookies 或 http.ResponseWriter.Header().Set,所有 Cookie 操作必须走框架封装接口。常见错误是手动构造 http.Cookie 后调用 http.SetCookie,这会导致 Header 冲突或被忽略。
正确做法是:
-
c.Cookie("name")读取单个 Cookie,返回*http.Cookie和 error;若不存在会报http.ErrNoCookie -
c.Cookies()获取全部 Cookie 切片,适合遍历或调试 -
c.SetCookie()写入,传入的是已初始化的*http.Cookie实例,不是键值对 - 注意:
http.Cookie.Expires和http.Cookie.MaxAge二选一即可,同时设可能被浏览器忽略
Session 中间件必须用 session.Middleware() 注册
Go Echo 自身不内置 Session 支持,依赖 echo-contrib/session 提供中间件。直接调用 session.Get() 而不注册中间件,会导致 sess == nil 或 panic。
关键点:
- 存储后端必须显式指定:文件系统(
sessions.NewFilesystemStore)、Redis(sessions.NewRedisStore)等,不能只 import 包就认为“有 session” -
sessionKey是加密密钥,长度建议 ≥ 32 字节;用短字符串(如"123")会导致crypto/aes报错 - 中间件注册必须在路由定义前,否则后续 handler 拿不到
session.Context - 同一 session 名(如
"user_session")在写入和读取时必须完全一致,大小写敏感
session.Values 是 map[string]interface{},类型断言容易 panic
从 sess.Values["key"] 取出的值是 interface{},直接赋给强类型变量(如 id := sess.Values["id"])不会报错,但运行时可能 panic —— 尤其当 key 不存在或类型不匹配时。
安全写法:
- 先检查 key 是否存在:
if val, ok := sess.Values["id"]; ok { ... } - 再做类型断言:
if id, ok := val.(string); ok { ... } - 避免直接用
sess.Values["id"].(string),没判空也没判类型 - 写入时也建议统一类型,比如用户 ID 始终存为
string,不要有时存int有时存string
Session 过期与 Cookie 生命周期必须协同配置
Session 数据本身有过期时间(sess.Options.MaxAge),但客户端 Cookie 也有独立生命周期(http.Cookie.MaxAge 或 Expires)。两者不一致会导致“用户以为还登录着,但服务端 session 已销毁”。
典型失配场景:
- 设置
sess.Options.MaxAge = 3600(1 小时),但 Cookie 的MaxAge = 0(会话级)→ 关闭浏览器即失效 - Redis 存储 session 时未同步设置 TTL,导致
gc_maxlifetime失效,旧 session 残留 - 跨子域名共享 session 时,
sess.Options.Domain漏设或设错(如写成"example.com"却访问"app.example.com")
真正起作用的是服务端 session 存储的 TTL 和客户端 Cookie 的过期时间两个值中更短的那个。别只改一边。










