基于React Hooks实现刷新保持登录态时session偶发校验失败问题
问题根因分析
- Axios跨域请求未配置携带Cookie:你服务端CORS已经开启了
credentials: true权限,但客户端发起请求时没有同步配置对应参数,导致浏览器不会稳定携带session关联的Cookie,服务端自然时有时无读不到session - express-session默认内存存储不稳定:官方自带的MemoryStore仅用于本地开发调试,不支持多进程、并发读写,服务端热重载、重启都会清空session,是你出现交替读取异常的核心原因
- session有效期配置错误:
expires属性需要传入Date对象,你直接填写毫秒数不会生效,应该使用maxAge属性配置有效期 - token取值时机问题:将token读取逻辑放在useEffect外部,组件初始化时仅取值一次,存在概率性读取不到刚写入的token的问题
修复方案
1. 修改客户端请求配置
调整app.js代码,新增跨域带Cookie的配置,同时把token读取移到useEffect内部:
useEffect(() => { // 用户已登录的情况下刷新页面保持登录态 const userAuthToken = localStorage.getItem('token'); Axios.post("http://localhost:3001/isUserAuth", { token: userAuthToken },{ withCredentials: true // 允许跨域请求携带Cookie,必须配置 }).then(response => { if (!response.data.auth) { setAuthStatus(false); console.log("NOT LOGGED IN!"); console.log(response.data.user); } else { setAuthStatus(true); console.log("LOGGED IN!"); console.log(response.data.user); } }) },[]);
2. 替换session为持久化存储
开发和生产环境都不要用默认内存存储,推荐用Redis、MongoDB等持久化存储,这里以Redis为例:
先安装依赖:npm i connect-redis redis
再调整服务端index.js的session配置:
const RedisStore = require('connect-redis')(session); const { createClient } = require('redis'); const redisClient = createClient({ legacyMode: true }); redisClient.connect().catch(console.error); app.use( session({ key: "userID", secret: "subscribe", // 生产环境请替换为长随机字符串 resave: false, saveUninitialized: false, store: new RedisStore({ client: redisClient }), // 新增Redis存储配置 cookie: { maxAge: 60 * 60 * 1000, // 替换expires为maxAge,单位为毫秒 httpOnly: true, // 禁止前端JS读取Cookie,提升安全性 } }));
如果不想部署Redis,也可以用connect-sqlite3等轻量文件存储替代。
3. 可选逻辑优化
你当前同时校验JWT和session,逻辑存在冗余,如果JWT本身已经包含用户身份信息,可以直接解析JWT后查询用户有效性,不需要依赖session存储,从根源上规避session读写异常的问题。如果需要保留双校验逻辑,请确认登录接口在登录成功后,已经正确给req.session.user赋值。
内容的提问来源于stack exchange,提问作者Jeff Meindring
相关产品推荐
相关产品推荐

