React应用收到Set-Cookie响应头但未保存Cookie问题求助
我搭建了一套简易登录系统,用户提交用户名和密码后,React前端会将数据POST至Express后端。输入正确数据时响应始终成功,但调用登录POST接口时,会话已创建且Cookie已返回至React应用,但该Cookie未被浏览器保存。
React端登录函数代码
async function login(event){ event.preventDefault(); setRequestState(REQUEST_STATE.pending) const request = `${SERVER_URL}/login`; const formData = new FormData(); formData.append("username",data["username"]) formData.append("password",data["password"]) const response = await fetch(request, { method: 'POST', body: formData, enctype:"multipart/form-data", credentials: 'same-origin', }) if (!response.ok) { if (response.status === 401) { console.log("username or password are incorrect") setDisplayError(response.status) } if (response.status === 500) { console.log("internal server error") setDisplayError(response.status) } setRequestState(REQUEST_STATE.no_request) return; } setRequestState(REQUEST_STATE.success) // navigate("/dashboard") }
Express会话配置代码
const express = require('express'); const cors = require('cors') const loginRouter = require('./src/routes/login.js'); const session = require('express-session') const app = express() app.use( cors({ origin:true, credentials:'same-origin', })) app.use(session({ secret: 'test', resave: false, saveUninitialized: false, // store: sessionStore, cookie: { secure: false, sameSite: 'none', } })); app.use(express.urlencoded({extended: true})) app.use('/login', loginRouter) app.listen(process.env.PORT ,()=>{ console.log(`Server is listening on port ${process.env.PORT}`) })
登录路由代码
const express = require('express') const multer = require('multer') const router = express.Router() const {getLogin,postLogin, authenticateLogin} = require('../controllers/login') upload = multer({}) router.post("/", upload.array(0), authenticateLogin, postLogin) router.get("/", getLogin) module.exports=router
登录控制器代码
const {pool} = require('../../sqlconfig') const bcrypt = require('bcrypt'); const postLogin = (req, res) => { return res.status(200).send({success:true}); } const getLogin = (req, res) => { // console.log("get this login betch") console.log(req.session.id) if(req.session.userId){ return res.status(200).send({success:true}); } // console.log("couldn't get login") return res.status(401).send({success:false}); } const authenticateLogin = async (req, res, next) => { const dict = JSON.parse(JSON.stringify(req.body)); const username = dict["username"]; const password = dict["password"]; if(!dict || !username || !password) { // console.log("Access deneid") return res.status(401).send({error:"Access denied"}); } try{ const query = "SELECT passwrd FROM admins WHERE admins.username=?"; const [result] = await pool.execute(query,[username]) if(result.length <= 0){ return res.status(401).send({error:"Access denied"}); } const passwordInDB = result[0].passwrd; if(!passwordInDB){ return res.status(401).send({error:"Access denied"}); } const match = await bcrypt.compare(password, passwordInDB); // console.log(match) if(!match){ return res.status(401).send({error:"Access denied"}); } const queryUserId = "SELECT id FROM admins WHERE admins.username=?"; const [resultUserId] = await pool.execute(queryUserId,[username]) req.session.userId = resultUserId[0].id; console.log("logged in successfuly!") console.log(req.session) next() } catch(e){ console.log(e) } } module.exports={ authenticateLogin, postLogin, getLogin }
问题排查与修复步骤
1. 调整前端Fetch的Credentials配置
将React登录函数中fetch的credentials: 'same-origin'改为credentials: 'include',跨域场景下浏览器才会处理Cookie的保存与携带:
const response = await fetch(request, { method: 'POST', body: formData, credentials: 'include', // 修改此处 })
注:enctype不是fetch的合法配置项,可直接移除,FormData默认采用multipart/form-data编码。
2. 修正后端CORS配置
将cors的credentials值改为true,同时建议明确指定前端域名(避免模糊匹配):
app.use( cors({ origin: 'http://localhost:3000', // 替换为你的前端实际域名 credentials: true, // 修改为true }) )
3. 调整Session Cookie的SameSite与Secure配置
HTTP环境(本地开发)下,sameSite: 'none'会被浏览器拒绝(该属性要求Cookie必须为Secure,即HTTPS环境),需改为'lax'或'strict':
app.use(session({ secret: 'test', resave: false, saveUninitialized: false, cookie: { secure: false, // HTTP环境设为false,HTTPS环境改为true sameSite: 'lax', // 修改为lax或strict } }));
若为HTTPS生产环境,可保持sameSite: 'none'并设置secure: true。
4. 简化FormData解析逻辑
无需通过JSON.parse(JSON.stringify(req.body))转换,直接从req.body获取参数即可:
const authenticateLogin = async (req, res, next) => { const username = req.body.username; const password = req.body.password; if(!username || !password) { return res.status(401).send({error:"Access denied"}); } // 后续代码不变 }
内容的提问来源于stack exchange,提问作者Amit Ritter
相关产品推荐
相关产品推荐

