You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axios获取response.headers['set-cookie']返回undefined问题求助

解决express-session + CORS下Cookie无法获取的问题

问题场景

用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:35:57