Express中Session读取异常求助:MongoStore存储后获取为undefined
问题:Express Session 在跨域请求中无法读取(MongoDB Atlas已存储但req.session为undefined)
我正在开发一个React应用,使用Express作为后端,通过MongoStore存储Session数据。登录MongoDB Atlas后可以看到Session已创建且变量已存储,但尝试访问Session时却得到undefined。
后端Express代码
const express = require('express'); const cors = require('cors'); const session = require('express-session'); const mongoose = require('mongoose'); const MongoDBStore = require('connect-mongodb-session')(session); const MONGODB_URI = "MY MONGODB ATLAS URL"; const store = new MongoDBStore({ uri: MONGODB_URI, collection: 'sessions' }); const app = express(); const port = process.env.PORT || 3001; app.use(cors()); app.use(session({ secret: 'mysecretkey', resave: false, saveUninitialized: false, store: store })); app.use(express.json()); app.get('/csrf', (req, res) => { if(req.headers['sec-fetch-site'] === 'same-site'){ const csrf = 'ABCDEFG'; req.session.csrf = csrf; req.session.save(err => { if (err) { console.log('Session save error:', err); return res.status(500).json({ error: 'Session save error' }); } console.log('CSRF Token set:', csrf); res.json({ csrf: csrf }); }); }else{ res.status(403).json({ error: 'Invaid Entry' }) } }); app.get('/test-get', (req, res) => { res.json({ message: req.session }) }) app.post('/login', (req, res) => { if(req.headers['sec-fetch-site'] === 'same-site'){ console.log('Session data on /login:', req.session); console.log('CSRF Token on /login:', req.session.csrf); if (req.session.csrf) { res.json({ message: 'Login successful', csrf: req.session.csrf }); } else { res.status(400).json({ error: 'CSRF token missing' }); } }else{ res.status(403).json({ error: 'Invaid Entry' }) } }) mongoose .connect(MONGODB_URI) .then(result => { app.listen(port, () => { console.log(`Server running on port ${port}`); }); }) .catch(err => { console.log(err); });
前端React代码
获取CSRF Token
const[csrf, setCSRF] = useState(''); useEffect(() => { fetch(PROCESSURL + 'csrf', { method: 'GET' }) .then((res) => res.json()) .then((data) => { setCSRF(data.csrf); }) .catch(() => { alert('Server: 403'); }) }, []);
登录提交
const handleSubmit = (event) => { event.preventDefault(); formData['csrf'] = csrf; fetch(PROCESSURL + 'login', { method: "POST", headers: { 'Content-Type': 'application/json', csrf: csrf }, body: JSON.stringify(formData) }) .then((res) => res.json()) .then((data) => { alert(data); }) }
解决方案
问题核心是跨域请求中Session Cookie未被正确传递,导致后端无法识别当前请求对应的Session。以下是具体修改步骤:
1. 修正CORS配置
默认cors()不允许携带凭证(Cookie),需明确配置允许凭证并指定前端Origin:
// 替换原app.use(cors()); app.use(cors({ origin: 'http://localhost:3000', // 替换为你的React前端实际地址 credentials: true // 允许携带Cookie }));
2. 完善Session的Cookie配置
跨域场景下需明确Cookie的SameSite和Secure属性,确保浏览器允许传递:
// 替换原session配置 app.use(session({ secret: 'mysecretkey', resave: false, saveUninitialized: false, store: store, cookie: { httpOnly: true, // 增强安全性,防止前端JS读取Cookie sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', // 生产环境HTTPS下用none,开发环境用lax secure: process.env.NODE_ENV === 'production' // 生产环境开启HTTPS时设为true } }));
3. 前端Fetch请求添加凭证参数
两段Fetch请求都需要加上credentials: 'include',确保Cookie被发送到后端:
获取CSRF的修改:
useEffect(() => { fetch(PROCESSURL + 'csrf', { method: 'GET', credentials: 'include' // 添加此行 }) .then((res) => res.json()) .then((data) => { setCSRF(data.csrf); }) .catch(() => { alert('Server: 403'); }) }, []);
登录请求的修改:
const handleSubmit = (event) => { event.preventDefault(); formData['csrf'] = csrf; fetch(PROCESSURL + 'login', { method: "POST", headers: { 'Content-Type': 'application/json', csrf: csrf }, credentials: 'include', // 添加此行 body: JSON.stringify(formData) }) .then((res) => res.json()) .then((data) => { alert(JSON.stringify(data)); // 建议转成字符串,否则alert会显示[object Object] }) }
关键原因说明
跨域请求时,浏览器默认会阻止Cookie的传递。只有当后端CORS配置允许凭证、前端请求明确携带凭证,且Cookie的SameSite/Secure属性符合浏览器安全规则时,Session Cookie才能被正确发送到后端,后端才能通过Cookie找到对应的Session数据(即使Atlas中已有存储,没有Cookie也无法关联到当前请求)。
内容的提问来源于stack exchange,提问作者Arogya
相关产品推荐
相关产品推荐

