You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go Gorilla Session部署在Apache Web Server时无法正常工作

Apache反向代理下Go会话Cookie失效问题排查

问题场景

本地运行带会话功能的Go登录表单代码正常,但部署到DigitalOcean Droplet的Apache反向代理环境后,登录成功重定向至/secret端点时,因Cookie未被正确携带而返回Forbidden。

Go会话登录代码

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/context"
    "github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte("super-secret"))

func loginAuthHandler(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    username := r.FormValue("username")
    password := r.FormValue("password")

    if password == "welcome" && username == "guest" {

        session, _ := store.Get(r, "session")
        session.Values["authenticated"] = true

        err := session.Save(r, w)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        http.Redirect(w, r, "/secret", http.StatusFound)
    } else {
        fmt.Fprintf(w, "Wrong Login!")
    }
}

func secret(w http.ResponseWriter, r *http.Request) {
    session, _ := store.Get(r, "session")

    if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
        http.Error(w, "Forbidden", http.StatusForbidden)
        return
    }

    fmt.Fprintf(w, "The cake is a lie!")

}

func main() {
    store.Options = &sessions.Options{
        Domain:   "localhost",
        Path:     "/",
        MaxAge:   3600 * 8,
        HttpOnly: true,
    }

    http.HandleFunc("/secret", secret)
    http.HandleFunc("/loginauth", loginAuthHandler)
    http.Handle("/", http.FileServer(http.Dir("public")))
    log.Fatal(http.ListenAndServe(":3003", context.ClearHandler(http.DefaultServeMux)))
}

Apache反向代理配置

#go
ProxyPass /go http://localhost:3003
ProxyPassReverse /go http://localhost:3003

环境差异导致的问题原因

  1. Cookie Domain不匹配:Go代码中硬设置Cookie的Domain为localhost,但部署后用户访问的是Droplet的实际域名(而非localhost),浏览器会拒绝携带针对localhost的Cookie到真实域名下。
  2. Cookie Path不匹配:反向代理使用/go前缀,而Go服务设置的Cookie Path为/。浏览器在访问/go/secret时,只会携带Path匹配/go或其子路径的Cookie,不会携带Path为/的Cookie。
  3. 反向代理请求头缺失:Apache默认未传递X-Forwarded-Host、X-Forwarded-Proto等头信息,导致Go服务无法感知实际的外部访问域名和协议,生成的Cookie不符合外部访问场景。

修复方案

  1. 修正Cookie Domain和Path:
    修改store.Options中的配置,适配反向代理环境:
    store.Options = &sessions.Options{
        Domain:   "your-droplet-domain.com", // 替换为实际域名,或留空让浏览器自动适配
        Path:     "/go/", // 匹配反向代理的前缀路径
        MaxAge:   3600 * 8,
        HttpOnly: true,
        SameSite: http.SameSiteLaxMode, // 可选,提升跨场景兼容性
    }
    
  2. 完善Apache反向代理配置:
    添加请求头传递,让Go服务获取正确的外部访问信息:
    #go
    ProxyPass /go http://localhost:3003
    ProxyPassReverse /go http://localhost:3003
    # 传递实际访问的Host和协议
    RequestHeader set X-Forwarded-Host "%{HTTP_HOST}e"
    RequestHeader set X-Forwarded-Proto "https" # 如果使用HTTPS,否则改为http
    
  3. 调整重定向路径:
    Go代码中登录成功后的重定向路径需改为/go/secret,适配反向代理的前缀:
    http.Redirect(w, r, "/go/secret", http.StatusFound)
    

内容的提问来源于stack exchange,提问作者Noel Garcia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 18:48:38