跨域请求不带Cookie是浏览器同源策略限制,非Gin框架bug;需前后端协同配置Access-Control-Allow-Credentials、动态Access-Control-Allow-Origin、Vary: Origin响应头,且Cookie的Domain须以点开头、secure与httpOnly按场景设置,前端请求必须启用withCredentials或credentials: 'include'。

跨域环境下 Cookie 无法自动携带,不是 Gin 框架的 bug,而是浏览器同源策略的强制行为;只要前后端配合正确设置 Access-Control-Allow-Credentials、Origin 和 Domain,就能稳定共享认证状态。
为什么跨域请求不带 Cookie?
浏览器默认禁止跨域请求携带 Cookie,这是同源策略的硬性限制,与 Gin 无关。即使后端设置了 Cookie,前端发起的跨域 fetch 或 axios 请求也不会自动附带它,除非显式声明信任。
- 错误现象:
Failed to load http://api.example.com/user: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. - 根本原因:前端设置了
withCredentials: true(或credentials: 'include'),但后端响应头仍用Access-Control-Allow-Origin: * - 必须改为动态返回请求头中的
Origin值,且不能是通配符
Gin 中设置跨域并允许 Cookie 携带
关键在于中间件中三处不可省略的响应头设置,缺一不可:
-
c.Header("Access-Control-Allow-Credentials", "true")—— 允许携带凭证(Cookie) -
c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))—— 动态回写 Origin,不能写死或用* -
c.Header("Vary", "Origin")—— 告诉 CDN 或代理缓存需按 Origin 分别缓存,避免缓存污染
注意:如果前端域名是 app.example.com,后端 Cookie 的 Domain 必须设为 .example.com(开头带点),否则浏览器拒绝发送。
立即学习“go语言免费学习笔记(深入)”;
设置认证 Cookie 时的参数陷阱
c.SetCookie() 的参数顺序和含义容易混淆,尤其在跨域场景下:
-
maxAge单位是秒,不是毫秒;设为-1表示会话级 Cookie(关闭浏览器即失效) -
domain必须以点开头(如".example.com"),且不能包含端口或协议 -
secure在 HTTPS 环境下必须为true,否则浏览器直接丢弃该 Cookie -
httpOnly设为true可防 XSS 窃取,但前端 JS 就无法读取(比如用于刷新 Token 的场景需权衡)
示例写法:c.SetCookie("session_id", token, 3600, "/", ".example.com", true, true)
前端必须同步开启 withCredentials
仅后端配置不够,前端所有跨域请求都得显式启用凭证传递:
- axios:
axios.get("/user", { withCredentials: true }) - fetch:
fetch("/user", { credentials: "include" }) - 原生 XHR:
xhr.withCredentials = true
漏掉任意一处,浏览器就当普通请求处理,Cookie 不会随请求发出,服务端也就查不到 session。
最易被忽略的是 Vary: Origin 头和 Domain 字段开头那个点——前者影响缓存行为,后者决定 Cookie 是否能被子域名共享;这两处出错,问题往往表现为“有时生效、有时失效”,排查起来特别耗时。


















