登录成功后如何在Golang中提取响应Cookie值?代码问题排查
问题修复方案
核心问题分析
代码出现后续请求重定向回登录页的原因主要有两点:
- 登录请求使用不完整URL,导致Cookie被存储在错误域名下,后续请求目标域名时无法携带有效会话Cookie
- 自定义Cookie Jar实现存在缺陷,未正确处理同名Cookie的更新与路径匹配逻辑
具体修复步骤
修正登录请求的完整URL
原代码中client.PostForm("domain.com", ...)使用了不完整的URL,会导致请求发送到http://domain.com而非目标HTTPS地址,Cookie被绑定到错误域名。需替换为完整的登录接口地址(可通过浏览器开发者工具查看登录表单的action属性确认):resp, err = client.PostForm("https://developer.domain.com.br/pt-BR/sign-in", url.Values{ "UserLogin[email]": {"xxxx"}, "UserLogin[password]": {"yyyyy"}, "csrf_token": {csrfToken}, })修复自定义Cookie Jar的实现
原Jar的SetCookies方法仅追加Cookie,未处理同名Cookie的更新;Cookies方法未过滤路径不匹配的Cookie。替换为严谨的实现:type Jar struct { sync.Mutex cookies map[string][]*http.Cookie } func NewJar() *Jar { return &Jar{ cookies: make(map[string][]*http.Cookie), } } func (jar *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) { jar.Lock() defer jar.Unlock() host := u.Host existingCookies := jar.cookies[host] updated := make([]*http.Cookie, 0) // 遍历新Cookie,替换同名同路径的旧Cookie for _, newCookie := range cookies { found := false for _, existing := range existingCookies { if existing.Name == newCookie.Name && existing.Path == newCookie.Path { updated = append(updated, newCookie) found = true break } } if !found { updated = append(updated, newCookie) } } jar.cookies[host] = updated } func (jar *Jar) Cookies(u *url.URL) []*http.Cookie { jar.Lock() defer jar.Unlock() host := u.Host cookies := jar.cookies[host] valid := make([]*http.Cookie, 0) // 过滤出路径匹配的Cookie for _, c := range cookies { if strings.HasPrefix(u.Path, c.Path) { valid = append(valid, c) } } return valid }完善资源释放与错误处理
每个HTTP响应的Body必须关闭以避免资源泄漏;同时不能忽略请求创建的错误:// 获取CSRF Token的请求示例 req, err := http.NewRequest("GET", "https://developer.domain.com.br/pt-BR/sign-in", nil) if err != nil { log.Fatal(err) } resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() // 必须关闭响应Body
完整修复后的代码
package main import ( "fmt" "github.com/PuerkitoBio/goquery" "io" "log" "net/http" "net/url" "strings" "sync" ) type Jar struct { sync.Mutex cookies map[string][]*http.Cookie } func NewJar() *Jar { return &Jar{ cookies: make(map[string][]*http.Cookie), } } func (jar *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) { jar.Lock() defer jar.Unlock() host := u.Host existingCookies := jar.cookies[host] updated := make([]*http.Cookie, 0) for _, newCookie := range cookies { found := false for _, existing := range existingCookies { if existing.Name == newCookie.Name && existing.Path == newCookie.Path { updated = append(updated, newCookie) found = true break } } if !found { updated = append(updated, newCookie) } } jar.cookies[host] = updated } func (jar *Jar) Cookies(u *url.URL) []*http.Cookie { jar.Lock() defer jar.Unlock() host := u.Host cookies := jar.cookies[host] valid := make([]*http.Cookie, 0) for _, c := range cookies { if strings.HasPrefix(u.Path, c.Path) { valid = append(valid, c) } } return valid } func NewJarClient() *http.Client { return &http.Client{ Jar: NewJar(), } } func fetch(w http.ResponseWriter, r *http.Request) { client := NewJarClient() // 获取CSRF Token req, err := http.NewRequest("GET", "https://developer.domain.com.br/pt-BR/sign-in", nil) if err != nil { log.Fatal(err) } resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() doc, err := goquery.NewDocumentFromResponse(resp) if err != nil { log.Fatal(err) } csrfToken := "" if val, ok := doc.Find(`head meta[name="csrf-token-value"]`).Attr("content"); ok { csrfToken = val } // 发送登录请求(修正完整URL) resp, err = client.PostForm("https://developer.domain.com.br/pt-BR/sign-in", url.Values{ "UserLogin[email]": {"xxxx"}, "UserLogin[password]": {"yyyyy"}, "csrf_token": {csrfToken}, }) if err != nil { log.Fatal(err) } defer resp.Body.Close() cookies := resp.Cookies() fmt.Println("获取到的Cookie:") for _, c := range cookies { fmt.Printf("名称: %s, 值: %s\n", c.Name, c.Value) } doc, err = goquery.NewDocumentFromResponse(resp) if err != nil { log.Fatal(err) } // 请求门户页面 req, err = http.NewRequest("GET", "https://developer.domain.com.br/pt-BR/developer/profile", nil) if err != nil { log.Fatal(err) } resp, err = client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() fmt.Println("响应状态:", resp.Status) doc, err = goquery.NewDocumentFromResponse(resp) if err != nil { log.Fatal(err) } html, _ := doc.Html() io.WriteString(w, html) } func main() { http.HandleFunc("/", fetch) log.Println("服务启动在 127.0.0.1:49721") log.Fatal(http.ListenAndServe("127.0.0.1:49721", nil)) }
内容的提问来源于stack exchange,提问作者luizfelipetx
相关产品推荐
相关产品推荐

