Axios获取response.headers['set-cookie']返回undefined问题求助
问题场景
用express-session、cors搭建后端服务,前端通过Axios和socket.io实现消息功能,尝试将消息payload与sessionId绑定,但遇到以下问题:
document.cookie始终返回undefined- 从Axios响应的
response.headers['set-cookie']获取Cookie时,该值也一直为undefined
相关代码
后端代码
import dotenv from "dotenv"; import cors from "cors"; import mongoose from "mongoose"; import session from "express-session"; import bodyParser from "body-parser"; import MongoStore from "connect-mongo"; import http from "http"; dotenv.config({ path: "./config.env" }); const app = express(); const server = http.createServer(app); import { Server } from "socket.io"; const DB = process.env.DATABASE_STRING.replace( "<password>", process.env.DATABASE_PASSWORD ); mongoose .connect(DB) .then(() => { console.log(`database connection was successfull ! :) \n`); }) .catch((error) => { console.log( `error - ${error} happened while attempting to connect to database :) \n ` ); }); console.log(process.env.SECRET); app.use(express.json()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use( cors({ origin: "http://localhost:5173", credentials: true, }) ); app.use( session({ secret: process.env.SECRET, resave: false, saveUninitialized: true, store: MongoStore.create({ mongoUrl: DB, collection: "sessions", // Collection name to store sessions ttl: 7 * 24 * 60 * 60, cookie: { secure: false }, }), cookie: { path: "/", secure: false, maxAge: 4 * 60 * 60 * 1000, }, }) ); app.get("/initialize-session", async (req, res) => { try { const sess = req.session; console.log(req.session, " --- req.session --- \n"); res.status(200).json({ message: "session init" }); } catch (error) { res.status(404).json({ message: `session init fail ${error}` }); } }); app.get("/chats/initiateChat", (req, res) => { console.log(`req recieved to chats/initiateChat endpoint`); }); app.get("/findPartner", (req, res) => { /* out of all sockets availabe select one randomly... */ console.log(` get request received to findPartner endpoint \n`); res.status(200).json({ message: "success" }); }); app.get("/authenticate-user", (req, res) => { console.log(req.headers.cookie, " --cookie--- "); res.status(200).json({ status: "success" }); }); const activeUsers = {}; const io = new Server(server, { cors: { origin: process.env.FRONTEND_ORIGIN, methods: ["GET", "POST"], credentials: true, }, }); io.on("connection", async (socket) => { console.log(socket.id, " ---socket user connected \n"); socket.on("chat-message", (msg) => { console.log("message: " + JSON.stringify(msg)); }); }); const PORT = process.env.PORT; server.listen(PORT, () => { console.log(` server listening on ${PORT}`); });
前端代码
import React, { useState } from "react"; import io from "socket.io-client"; import { v4 as uuidv4 } from "uuid"; import axios from "axios"; export const ChatPage = () => { const [message, setMessage] = useState(""); const handleMessageTransmission = (e) => { e.preventDefault(); const socket = io("http://localhost:6040", { headers: { "Content-Type": "application/json", }, withCredentials: true, }); if (message) { console.log(`this is the message ${message}`); const uniqueId = uuidv4(); socket.emit("chat-message", { message }); } axios .get("http://localhost:6040/authenticate-user", { withCredentials: true, }) .then((response) => { console.log( response.headers['set-cookie'] , " cookie ") }) .catch((error) => {}); }; return ( <div id="Chat-Page-Main" className="w-screen h-screen bg-bg3 flex flex-col " > <div id="Chat-Container" className="flex flex-col w-full flex-grow"> </div> <form id="Send-Message-form" className="flex flex-row justify-evenly p-2 sm:p-4 h-24 bg-bg2" method="post" onSubmit={(e) => handleMessageTransmission(e)} > <div id="Profile-Image-Wrapper" className="flex flex-col items-center justify-center " > <img src="/avatardummy.png" id="Profile-Dummy" className="rounded-full w-12 h-12" /> </div> <input type="text" className="flex-grow rounded-md m-2" placeholder="Hi..." onChange={(e) => setMessage(e.target.value)} /> <button id="Send-Message-Button" className=" rounded-md shadow-md text-center" > Send </button> </form> </div> ); };
解决方案及修改点
1. 先触发Session初始化
当前前端未调用/initialize-session接口,后端还未创建Session,自然不会返回Set-Cookie头。需在前端组件挂载时先调用该接口:
import React, { useState, useEffect, useRef } from "react"; // ... 其他导入 export const ChatPage = () => { const [message, setMessage] = useState(""); const socket = useRef(null); useEffect(() => { // 初始化Session axios.get("http://localhost:6040/initialize-session", { withCredentials: true }) .then(res => console.log("Session initialized")) .catch(err => console.error(err)); // 初始化Socket连接(复用连接,避免每次发送新建) socket.current = io("http://localhost:6040", { withCredentials: true }); return () => { if (socket.current) socket.current.disconnect(); }; }, []); // ... 其他代码 };
2. 统一CORS配置并暴露Set-Cookie头
跨域场景下,浏览器默认不会让前端访问Set-Cookie头,需在后端CORS配置中显式暴露;同时保证express和socket.io的CORS origin一致:
// 后端CORS配置修改 app.use( cors({ origin: "http://localhost:5173", // 和socket.io的origin保持一致,建议用process.env.FRONTEND_ORIGIN统一管理 credentials: true, exposedHeaders: ['Set-Cookie'] // 暴露Set-Cookie头给前端 }) ); // socket.io的CORS配置修改 const io = new Server(server, { cors: { origin: "http://localhost:5173", // 和express的origin统一 methods: ["GET", "POST"], credentials: true, }, });
3. 规范express-session的Cookie配置
移除store中的重复Cookie配置,统一到session的cookie选项中,并完善安全配置:
app.use( session({ secret: process.env.SECRET, resave: false, saveUninitialized: true, store: MongoStore.create({ mongoUrl: DB, collection: "sessions", ttl: 7 * 24 * 60 * 60 // 移除此处的cookie配置,避免冲突 }), cookie: { path: "/", secure: false, // 开发环境设为false,生产环境必须设为true(HTTPS) maxAge: 4 * 60 * 60 * 1000, httpOnly: true, // 默认开启,防止XSS攻击,这也是document.cookie拿不到Cookie的原因(正常安全行为) sameSite: 'lax' // 开发环境用lax,跨域生产环境用none(需配合secure: true) }, }) );
4. 复用Socket连接
当前每次发送消息都会新建Socket连接,导致Session不匹配,需将Socket实例存入useRef复用:
const handleMessageTransmission = (e) => { e.preventDefault(); if (message && socket.current) { socket.current.emit("chat-message", { message }); setMessage(""); // 发送后清空输入框 } axios.get("http://localhost:6040/authenticate-user", { withCredentials: true }) .then((response) => { console.log(response.headers['set-cookie'], " cookie ") }) .catch((error) => {}); };
关键说明
httpOnly: true是安全配置,会阻止前端通过document.cookie获取Cookie,这是正常的安全行为,无需修改。如果需要在前端关联Session,可通过后端接口返回SessionId(不推荐),或直接依赖浏览器自动携带Cookie到后端请求。- 跨域时,Cookie的
sameSite属性需根据场景设置:同域用strict/lax,跨域生产环境用none(必须配合secure: true,即HTTPS环境)。
内容的提问来源于stack exchange,提问作者DaObliterator
相关产品推荐
相关产品推荐

