Chrome 120+等现代浏览器会静默丢弃缺失SameSite、Secure或路径域名不匹配的Cookie;SPA中fetch/axios默认不带Cookie,须显式设置credentials: 'include'或withCredentials: true,并配合后端CORS头Access-Control-Allow-Credentials: true及非通配Origin。

直接用 c.SetCookie() 写,但必须配合 SameSite、Secure 和域名路径配置,否则现代浏览器(尤其是 Chrome 120+)会静默丢弃 Cookie。单页应用(SPA)下前端走 fetch 或 axios 发请求时,不加 credentials: 'include' 就根本带不上 Cookie。
为什么 SPA 请求带不上 Cookie?
浏览器默认对跨域请求(哪怕只是前端端口不同,如 http://localhost:5173 → http://localhost:8080)禁用 Cookie 携带。这不是 Echo 的问题,是 Fetch API 的安全策略。
- 前端必须显式声明:
fetch("/login", { credentials: "include" })或 axios 配置withCredentials: true - 后端响应头必须包含
Access-Control-Allow-Origin具体值(不能是*),例如http://localhost:5173 -
Access-Control-Allow-Credentials: true必须返回,否则浏览器拒绝写入 Cookie
c.SetCookie() 怎么设才不会被浏览器忽略?
只写 name=value 不够,Chrome 和 Safari 对缺失关键属性的 Cookie 会直接丢弃(不报错、不提示)。常见失效组合是没设 SameSite 或 Secure 却在 HTTPS 环境下发。
- 开发环境(HTTP):设
SameSite= lax,Secure=false,HttpOnly=true(防 XSS 读取) - 生产环境(HTTPS):必须设
Secure=true,SameSite= strict或lax(推荐lax平衡安全与可用性) - 路径必须匹配前端路由前缀,比如前端所有请求都走
/api/xxx,就设Path="/api";若要全站生效,用Path="/" - 域名注意:本地开发用
Domain="localhost"即可;部署到子域名(如app.example.com)且需共享 Cookie 时,才设Domain=".example.com"(开头带点)
前端读不到 Cookie?别碰 document.cookie
如果后端设置了 HttpOnly=true(强烈建议),前端 JavaScript 就完全无法通过 document.cookie 读取该 Cookie —— 这是故意设计的安全隔离。这时候不要尝试绕过,而是让后端在登录成功响应体里附带必要字段(如用户 ID、角色),前端存进 localStorage 仅作 UI 展示用。
- 真正需要服务端验证的状态(如登录态、权限)必须靠每次请求携带 Cookie,由后端中间件校验
- 前端自己从
document.cookie解析出的值不可信,不能用于权限判断或身份标识 - 若确实需要前端读写(比如语言偏好),单独建一个非
HttpOnly的 Cookie,命名区别开(如ui_lang而不是session_id)
Session 与 Cookie 生命周期怎么对齐?
Echo 本身不处理 Session 过期逻辑,全靠 echo-contrib/session 中间件和存储后端配合。最容易出问题的是:Cookie 还活着,但 Session 数据在 Redis 里已删了,导致 sess.Values 为空。
- 设置
sess.Options.MaxAge(Session 数据有效期)必须 ≤ Cookie 的MaxAge,否则会出现“Cookie 有效但 Session 找不到” - 文件系统存储(
FilesystemStore)不支持自动清理过期 Session,上线前务必换 Redis 或数据库后端 - 前端登出时,除了调后端
/logout接口清 Session,还要手动删客户端 Cookie:document.cookie = "session_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"
最常被忽略的一点:Chrome 124+ 开始对 SameSite=Lax 下重定向(302)后的 Cookie 设置也做了更严限制——如果重定向目标是跨站的,即使满足 Lax 条件,Cookie 也可能不写入。所以登录成功后尽量避免 302 跳转,改用 200 响应体返回 token 或用户信息,由前端 JS 控制跳转。











