Session Cookie深度解析与前端开发中的常见问题处理
又踩坑了,Session Cookie居然丢了
最近在开发一个后台管理系统的时候,遇到一个特别诡异的问题:用户登录状态总是莫名其妙丢失。折腾了半天发现是Session Cookie出了问题。这里我踩了个坑,花了整整一天才解决,记录下来给大家避个雷。
事情是这样的,我在用Express做后端,前端用Vue 3写的单页应用。登录功能调用后端接口返回用户信息,同时设置了一个HttpOnly的Session Cookie。按道理说,这个Cookie应该自动带上每次请求的,但实际测试时发现,某些情况下它就是不带!尤其是生产环境部署到Nginx上之后,这个问题更明显。
排查过程真是折磨人
最开始我以为是前端的问题,检查了axios的配置:
// axios配置
import axios from 'axios'
const instance = axios.create({
baseURL: 'https://jztheme.com/api',
withCredentials: true // 这里要记得开启跨域凭证
})
export default instance
这里要注意,withCredentials必须设置为true,不然浏览器不会发送Cookie。我当时就忘了设置这个,导致调试了半天才发现问题。不过改完之后问题还是存在,这让我很抓狂。
后来试了下发现,原来是后端CORS配置有问题。我的Express代码最初是这样写的:
// 原始CORS配置
const cors = require('cors')
app.use(cors())
这里我踩了个大坑,默认的cors()配置不会允许携带凭证。正确的写法应该是:
// 正确的CORS配置
const cors = require('cors')
app.use(cors({
origin: 'https://your-frontend-domain.com', // 生产环境要指定具体域名
credentials: true // 允许携带凭证
}))
核心代码就这几行
经过一番折腾,最终确定完整的解决方案如下:
后端Express部分:
// session配置
const session = require('express-session')
app.use(session({
secret: 'my-secret-key',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production', // 生产环境必须是true
sameSite: 'none' // 跨站请求必须设置为none
}
}))
// CORS配置
const cors = require('cors')
app.use(cors({
origin: process.env.NODE_ENV === 'production'
? 'https://your-frontend-domain.com'
: 'http://localhost:3000',
credentials: true
}))
前端Vue部分:
// axios配置
import axios from 'axios'
const instance = axios.create({
baseURL: process.env.NODE_ENV === 'production'
? 'https://jztheme.com/api'
: 'http://localhost:5000/api',
withCredentials: true
})
export default instance
这里有几个重要细节
- secure属性:生产环境下必须设置为true,否则Chrome会直接拒绝发送Cookie
- sameSite属性:现代浏览器要求跨站请求必须显式设置为’none’
- CORS的origin:不能使用通配符*,必须指定具体的前端域名
- HTTPS:生产环境一定要用HTTPS,不然secure为true时Cookie无效
这里有个小插曲,改完这些配置后,本地开发环境反而出问题了。原因是本地一般用HTTP,而secure设为true后Cookie就不生效了。最后我通过判断环境变量解决了这个问题:
secure: process.env.NODE_ENV === 'production'
还有个小问题待解决
虽然主要问题解决了,但现在偶尔还会出现第一次登录失败的情况。我怀疑是Nginx代理层的配置问题,暂时还没完全搞明白。目前的临时解决方案是让前端重试一次登录请求:
// 登录重试逻辑
async function login(payload) {
try {
const res = await api.post('/auth/login', payload)
return res.data
} catch (error) {
if (error.response.status === 401) {
// 第一次失败重试一次
return api.post('/auth/login', payload)
}
throw error
}
}
以上是我踩坑后的总结
这次经历让我对Session Cookie的理解更深了。以前总觉得设置个HttpOnly就万事大吉,没想到还有这么多坑。尤其是现代浏览器的安全策略越来越严格,像sameSite这种新特性很容易被忽视。
如果你也遇到类似的问题,或者有更好的解决方案,欢迎在评论区交流。毕竟前端安全这块水挺深的,大家一起探讨才能进步嘛。

暂无评论