martini 应用中使用 `martini-contrib/sessions` 时,session 数据在请求间丢失,通常因中间件执行顺序不当或响应未正确提交 cookie 导致;本文详解正确配置 cookie store、确保中间件顺序、避免提前终止请求等关键修复步骤。
在 Martini 框架中,Session 跨请求失效是一个常见但易被忽视的问题。从你提供的代码来看,逻辑本身(如 session.Set() 和 session.Get())并无语法错误,但实际运行中 /session 接口返回空结构体,说明 Session 数据未能持久化到后续请求——根本原因几乎总是 HTTP 响应未携带有效的 Set-Cookie 头,导致浏览器无法保存或回传 session ID。
Martini 的 sessions.Sessions() 是一个 全局中间件(Global Middleware),必须通过 m.Use(...) 在路由注册前启用,且需确保:
你当前的 /login 处理函数存在两个高危问题:
m.Get("/login", binding.Bind(LoginForm{}), func(r render.Render, session sessions.Session, form LoginForm) string {
// ✅ 正确使用数据库连接(连接池复用,无需 defer conn.Close)
conn, err := sql.Open("sqlite3", "ocdns.db")
if err != nil {
log.Printf("DB open failed: %v", err)
return "DB error"
}
defer conn.Close() // ✅ 此处 defer 安全:conn 是本次请求获取的句柄(实际是池中连接)
stmt, err := conn.Prepare(`
SELECT user_id, username, name_first, name_last, role, team_id
FROM User
WHERE username = ? AND password = ?
LIMIT 1;
`)
if err != nil {
log.Printf("Prepare failed: %v", err)
return "SQL prepare error"
}
defer stmt.Close()
var id, username, name_first, name_last, role, team_id string
err = stmt.QueryRow(form.Username, form.Password).Scan(
&id, &username, &name_first, &name_last, &role, &team_id,
)
if err != nil {
if err == sql.ErrNoRows {
log.Printf("Login failed for user: %s", form.Username)
return "Bad" // ✅ 不 panic,确保响应发出
}
log.Printf("Query error: %v", err)
return "DB query error"
}
// ✅ 安全写入 Session
session.Set("id", id)
session.Set("username", username)
session.Set("name_first", name_first)
session.Set("name_last", name_last)
session.Set("role", role)
session.Set("team_id", team_id)
// ✅ 强制刷新 Session(可选但推荐,确保 Cookie 立即写入响应头)
session.Sa
ve()
log.Printf("Login OK for user: %s", username)
return "OK"
})store := sessions.NewCookieStore([]byte("your-32-byte-secret-key-here"))
store.Options(sessions.Options{
Path: "/",
MaxAge: 86400, // 24h
HttpOnly: true,
Secure: true, // 仅 HTTPS 传输(部署到 HTTPS 环境时启用)
SameSite: http.SameSiteLaxMode,
})
m.Use(sessions.Sessions("my_session", store))Session 跨请求失效 ≠ Session 代码写错,而是 HTTP 协议层契约未履行:服务器必须在首次写入 Session 时,通过 Set-Cookie 告诉浏览器“请记住这个 ID”;浏览器则需在后续请求中通过 Cookie 头回传它。只要确保:
你的 Session 就能稳定工作。调试时优先检查网络面板中的 Cookie 交互,而非仅关注 Go 代码逻辑。