Go 官方只有 http.cookie,没有官方的 Session 包。

也就是说:

  • Cookie:官方一等公民
  • Session:官方不提供
一、Go 官方对 Cookie 的支持(很完整)

在标准库里,Cookie 是完整内建的

相关 API 都在:

net/http
二、那为什么 Go 官方不提供 Session?

这是设计哲学问题

1、session ≠ HTTP 标准

  • Cookie 是HTTP 标准的一部分
  • Session 是应用层概念
  • Session 的实现方式五花八门:
    • 内存
    • Redis
    • 文件
    • JWT(甚至没 Session)

官方没法“选边站”

2、Go 的设计哲学:最小但通用

Go 官方库的原则是:

只做通用、底层、稳定的东西

Session 涉及:

  • 存储方案
  • 过期策略
  • 分布式
  • 安全策略
  • 业务模型

一旦官方出 Session:

  • 就等于帮你做架构决策
  • 很容易限制场景
3、对比一下其他语言你就懂了PHP

$_SESSION["user_id"] = 1;

简单,但:

  • 强绑定 Cookie
  • 强绑定文件 / 内存
  • 不利于分布式
Java(Servlet)

HttpSession session = Request.getSession();

重、复杂、历史包袱

Go

“我给你工具,你自己搭积木”
三、那 Go 官方有没有“接近 Session 的东西”?有,但很底层1、context.Context❌ 不是 Session

ctx := r.Context()
  • 只在一次请求链路内
  • 不跨请求
  • 用于超时 / 取消 / trace

不能用来做登录态

2、http.Request/ResponseWriter

只负责:

  • Header
  • Cookie
  • Body

不碰业务状态

四、Go 社区是怎么解决 Session 的?常用第三方库1、gorilla/sessions(最经典)

store := sessions.NewCookieStore([]byte("secret"))session, _ := store.Get(r, "mysession")session.Values["user_id"] = 1session.Save(r, w)

支持:

  • Cookie
  • Filesystem
  • Redis(插件)
2、gin-contrib/sessions(Gin 生态)

sessions.Default(c).Set("user_id", 1)
五、Go 官方“默认推荐”的方式是什么?

不是 Session,而是:

自己实现 / 使用第三方 / 或用 Token(JWT)

所以你会看到很多 Go 项目:

  • 微服务:JWT / OAuth
  • 单体 Web:Session + Redis
  • API 服务:Token + Header
六、一个完整实现示例6.1、示例目标

实现一个最小但完整的登录系统:

  • /login:登录,创建 Session
  • /profile:需要登录才能访问
  • /logout:退出登录,销毁 Session

技术点:

  • Cookie 保存 session_id
  • 服务端内存保存 Session
  • 中间件校验登录态
6.2、整体结构

请求└── Cookie: session_idGo Server├── SessionStore(map)├── 登录校验└── 业务处理
6.3、完整可运行代码
直接 go run main.go 就能用

package mainimport ("fmt""log""math/rand""net/http""sync""time"// ===== 1. Session 结构 =====type Session struct {UserID    intUsername  stringExpiresAt time.Time// ===== 2. Session 存储 =====var (sessionStore = make(map[string]*Session)mu           sync.Mutex// ===== 3. 生成 SessionID =====func newSessionID() string {return fmt.Sprintf("%d_%d", time.Now().UnixNano(), rand.Int())// ===== 4. 创建 Session =====func createSession(w http.ResponseWriter, userID int, username string) {sid := newSessionID()mu.Lock()sessionStore[sid] = &Session{UserID:    userID,Username: username,ExpiresAt: time.Now().Add(30 * time.Minute),mu.Unlock()http.SetCookie(w, &http.Cookie{Name:     "session_id",Value:    sid,Path:     "/",HttpOnly: true,// ===== 5. 获取 Session =====func getSession(r *http.Request) (*Session, bool) {cookie, err := r.Cookie("session_id")if err != nil {return nil, falsemu.Lock()defer mu.Unlock()sess, ok := sessionStore[cookie.Value]if !ok {return nil, falseif sess.ExpiresAt.Before(time.Now()) {delete(sessionStore, cookie.Value)return nil, falsereturn sess, true// ===== 6. 销毁 Session =====func destroySession(w http.ResponseWriter, r *http.Request) {cookie, err := r.Cookie("session_id")if err == nil {mu.Lock()delete(sessionStore, cookie.Value)mu.Unlock()http.SetCookie(w, &http.Cookie{Name:   "session_id",Value: "",Path:  "/",MaxAge: -1,// ===== 7. 登录接口 =====func loginHandler(w http.ResponseWriter, r *http.Request) {// 模拟账号校验username := r.FormValue("username")password := r.FormValue("password")if username != "admin" || password != "123456" {w.WriteHeader(http.StatusUnauthorized)w.Write([]byte("login failed"))returncreateSession(w, 1, username)w.Write([]byte("login success"))// ===== 8. 需要登录的接口 =====func profileHandler(w http.ResponseWriter, r *http.Request) {sess, ok := getSession(r)if !ok {w.WriteHeader(http.StatusUnauthorized)w.Write([]byte("please login"))returnw.Write([]byte("hello " + sess.Username))// ===== 9. 退出登录 =====func logoutHandler(w http.ResponseWriter, r *http.Request) {destroySession(w, r)w.Write([]byte("logout success"))// ===== 10. main =====func main() {rand.Seed(time.Now().UnixNano())http.HandleFunc("/login", loginHandler)http.HandleFunc("/profile", profileHandler)http.HandleFunc("/logout", logoutHandler)log.Println("server running at :8080")log.Fatal(http.ListenAndServe(":8080", nil))
6.4、如何测试(一步步来)1、登录

curl -i -X POST \-d "username=admin&password=123456" \http://localhost:8080/login

你会看到:

Set-Cookie: session_id=xxx; HttpOnly
2、带 Cookie 访问受保护接口

curl -b "session_id=xxx" http://localhost:8080/profile

输出:

hello admin
3、退出登录

curl -b "session_id=xxx" http://localhost:8080/logout
6.5、这套代码覆盖的核心点
  • ✔ SessionID 随机生成
  • ✔ Cookie + HttpOnly
  • ✔ Session 过期时间
  • ✔ 并发安全(sync.Mutex)
  • ✔ 登录 / 校验 / 退出完整流程
6.6、真实项目需要改动的地方

一定要改的地方:

  1. map ➜Redis
  2. SessionID ➜更强随机(UUID / crypto/rand)
  3. 加:
  4. HTTPS
  5. Secure Cookie
  6. CSRF 防护
  7. Session 自动续期(滑动过期)
6.7、一句话总结
登录本质就是:服务器创建 Session,客户端保存 SessionID,之后每次请求用 SessionID 找回用户身份。