登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go 客户端怎么保存 Cookie 并连续请求接口

来源:17golang原创

时间:2026-09-06 01:40:24 104浏览 收藏

Go 客户端要连续访问登录接口和业务接口,关键是复用同一个 http.Client,并给它配置一个 cookiejar.Jar。登录响应里的 Set-Cookie 会由 Client 自动交给 Jar 保存,下一次请求再按 URL 的匹配规则取回 Cookie;不要把响应头里的整段字符串手动复制到下一个请求。

最小可用组合是:一个逻辑会话对应一个 Jar,一个 Client 持有这个 Jar,所有连续请求都使用这个 Client。Jar 默认在内存中工作,不负责把登录态写入磁盘。
要点速览
  • http.Client.Jar 同时负责接收响应 Cookie 和为后续请求注入匹配 Cookie。
  • Cookie 是否发送由协议、域名、路径、Secure、过期时间等属性共同决定。
  • 多账号或多租户场景不要共用一个 Jar;生产环境建议配置 publicsuffix.List

先把 cookiejar.Jar 绑定到同一个 http.Client

cookiejar.New(nil) 可以创建一个内存 Cookie Jar。将它放进 Client 的 Jar 字段后,Client 会在发出请求前查找匹配 Cookie,并在收到响应后更新 Jar。下面的地址是示例接口,重点在会话对象的连接方式。

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "net/http/cookiejar"
    "net/url"
    "strings"
)

func main() {
    // 一个 Jar 代表一个登录会话,不能在多个账号之间混用。
    jar, err := cookiejar.New(nil)
    if err != nil {
        log.Fatal(err)
    }
    client := &http.Client{Jar: jar}

    // 登录响应如果包含 Set-Cookie,Client 会自动交给 Jar 保存。
    loginBody := strings.NewReader(`{"username":"demo","password":"secret"}`)
    loginReq, err := http.NewRequest(http.MethodPost, "https://api.example.test/login", loginBody)
    if err != nil {
        log.Fatal(err)
    }
    loginReq.Header.Set("Content-Type", "application/json")
    loginResp, err := client.Do(loginReq)
    if err != nil {
        log.Fatal(err)
    }
    io.Copy(io.Discard, loginResp.Body)
    loginResp.Body.Close()

    // 继续使用同一个 Client,业务请求会自动携带可匹配的 Cookie。
    profileResp, err := client.Get("https://api.example.test/profile")
    if err != nil {
        log.Fatal(err)
    }
    defer profileResp.Body.Close()
    fmt.Println(profileResp.Status)

    // Cookies 只用于观察某个 URL 当前能取到哪些 Cookie,不是持久化接口。
    profileURL, _ := url.Parse("https://api.example.test/profile")
    for _, c := range jar.Cookies(profileURL) {
        fmt.Println(c.Name, c.Value)
    }
}

这里的核心不是调用两次 Get,而是始终保留 client 这个会话容器。若每次请求都写成 &http.Client{},或者登录后换了一个没有同一 Jar 的 Client,后续接口自然看不到登录态。

按域名、路径和协议排查 Cookie 为什么没发送

帮助读者把 Cookie 是否可用拆成 URL 与属性之间的静态判断边界。
图2:查看 URL 匹配边界与 Cookie 属性边界,定位 jar.Cookies 为空或业务请求未带 Cookie 的原因。

Jar 不会把所有 Cookie 无条件塞进每个请求。它按照 Cookie 属性和目标 URL 计算“这次能不能带”,因此排查时先把请求 URL 写清楚,再观察 jar.Cookies(u) 的结果。

检查项常见现象处理思路
SchemeCookie 标记了 Secure,但请求使用 HTTP改用 HTTPS,或在测试环境明确区分安全与非安全 Cookie
Domain登录在一个主机,业务请求换了无关域名确认服务端设置的 Domain 与目标主机匹配,不要手动扩大范围
Path同域名不同路径的接口拿不到 Cookie查看 Set-Cookie 的 Path,接口路径不在范围内时不会发送
过期时间第一次请求成功,过一段时间后失效检查 Expires 或 Max-Age,并准备重新登录或刷新会话

jar.Cookies 返回的是指定 URL 当前可用的 Cookie,适合定位“Jar 里有没有”和“这个 URL 能不能拿到”两类问题。它不是把所有内部状态导出的调试快照;如果 URL 不是 HTTP 或 HTTPS,Cookie 列表也会为空。

Go http.Client、cookiejar.Jar、Set-Cookie 与业务请求之间的会话结构关系
图1:查看同一会话中 http.Client 与 cookiejar.Jar 的静态关系,理解 Set-Cookie 如何成为后续请求的可用状态。

为跨子域场景配置 PublicSuffixList

直接传入 nil 作为 Options 对测试很方便,但官方文档明确提示:没有公共后缀列表时,某些域名边界判断会变得不安全。真实服务通常应引入 golang.org/x/net/publicsuffix,让 Jar 能识别 co.uk 这类公共后缀。

# 引入官方 Go 扩展包,让 Cookie Jar 使用公共后缀规则
go get golang.org/x/net/publicsuffix
import (
    "log"
    "net/http"
    "net/http/cookiejar"

    "golang.org/x/net/publicsuffix"
)

func newSessionClient() *http.Client {
    // 公共后缀列表限制 Cookie 的可设置域边界,生产环境不要省略。
    jar, err := cookiejar.New(&cookiejar.Options{
        PublicSuffixList: publicsuffix.List,
    })
    if err != nil {
        log.Fatal(err)
    }
    return &http.Client{Jar: jar}
}

这项配置不会让不同站点共享登录态,作用恰恰是防止服务端越过公共后缀设置过宽的 Cookie。若业务只访问单一主机,它仍然是一个成本很低的安全默认值。

按用户隔离 Jar 并处理内存与并发边界

Client 和符合约定的 CookieJar 可以安全地被多个 goroutine 使用,但“线程安全”不等于“账号隔离”。一个 Jar 里放的是同一逻辑会话的状态;多账号并发时应为每个账号创建独立 Jar 和 Client,避免请求携带错误用户的 Cookie。

另外,cookiejar.Jar 是内存实现,进程重启后登录态不会自动恢复。如果必须跨重启保留会话,需要明确设计持久化 Cookie 的格式、加密和过期清理,并实现自己的 http.CookieJar 或在应用层保存刷新令牌。不要把 Cookie 值直接写入普通日志。

常见问题

为什么登录成功,下一次请求仍然未登录?

最常见原因是换了 Client、没有配置 Jar,或业务 URL 不符合 Cookie 的 Domain、Path、Scheme 与过期条件。先用同一 URL 调用 jar.Cookies 查看匹配结果。

能不能直接复制响应头里的 Set-Cookie?

不建议。手动复制容易带入属性文本、忽略过期和域名规则;让 Client 与 Jar 管理 Cookie 更接近 HTTP 的实际语义。

一个 Cookie Jar 能不能给所有用户共用?

不应该。Jar 可以并发安全地访问,但其中的状态属于会话;多用户服务应按账号、租户或登录上下文隔离。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>