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

使用express-session在Express中无法访问会话数据的问题排查

问题:Express-session会话数据在Nuxt.js Axios请求中无法获取

我在Node.js应用中使用express-session + connect-session-sequelize管控会话,将数据存储到MySQL数据库。登录成功后通过以下代码设置会话数据:

req.session.user = {
  id: user.id,
  email: user.email
};

但后续Nuxt.js前端通过Axios发起API调用时,req.session.user始终为undefined,无法获取会话数据。


服务端配置代码

import express from 'express';
import cors from 'cors';
import { sequelize } from './Database/Models/index';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import usersRoute from './Routers/usersRoute';
import checkAuthenticated from './Middlewares/checkAuthenticated';

const app = express();

app.use(cookieParser())
const SequelizeStore = require("connect-session-sequelize")(session.Store);
var myStore = new SequelizeStore({
  db: sequelize,
  checkExpirationInterval: 15 * 60 * 1000, 
  expiration: 24 * 60 * 60 * 1000  
});

app.use(
  session({
    secret: 'secret',
    cookie: {
      secure: false
    },
    saveUninitialized: false,
    resave: false,
    unset: 'destroy'
  }),
);

myStore.sync();

app.use(
  cors({
    origin: [
      'http://localhost:3000',
      'https://localhost:3000'
    ],
    credentials: true,
    exposedHeaders: ['set-cookie']
}))

认证中间件代码

const checkAuthenticated = (req: any, res: any, next: any) => {
  if (req.session && req.session.user) {
    console.log(req.session.user)
    res.json({ loggedIn: true });
    next();
  } else {
    console.log(req.session)
    res.json({ loggedIn: false });
  }
};

export default checkAuthenticated;

登录接口代码

export const loginUser = async (req: any, res: any) => {
  try {
    const { error, value } = loginSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ error: error.details[0].message });
    }
    const user = await serviceLoginUser(value);

    req.session.user = {
            id: user.id,
            email: user.email,
        };
    res.status(200).json({Login: true, user: req.session.user});
  } catch (error: any) {
    const statusCode = error.code || 500;
    console.log(error.message)
    res.status(statusCode).json({ error: error.message });
  }
}

前端Axios调用代码

<script setup>
  import { ref } from 'vue';
  import axios from 'axios';

  axios.defaults.withCredentials = true;

  const email = ref('');
  const password = ref('');
  const showPassword = ref(false);
  const errors = ref('');
  
  const togglePasswordVisibility = () => {
    showPassword.value = !showPassword.value;
  };
  
  const handleSubmit =  async () => {
    try {
      await axios.post("http://localhost:4000/users/signin", {
        email: email.value,
        password: password.value
      }
      , {
      withCredentials: true
      });
      await navigateTo('/')
    } catch (error) {
      console.log(error)
    }
  }
</script>

问题成因

  1. Session未关联SequelizeStore:创建了myStore但未在session配置中指定store: myStore,导致会话默认存在内存中,未持久化到MySQL,跨请求易丢失。
  2. 中间件顺序错误:CORS中间件在session之后执行,OPTIONS预检请求会先经过session处理,引发跨域凭证传递问题。
  3. 缺少JSON解析中间件:服务端未配置express.json(),可能导致登录接口无法正确解析请求体(若路由未单独配置)。
  4. Cookie配置不完整:跨域场景下未设置sameSite属性,浏览器可能拒绝携带会话Cookie。
  5. 认证中间件逻辑错误:先返回响应再调用next(),会导致后续路由无法执行,且触发重复响应的潜在问题。

修复方案

1. 修正服务端中间件配置

调整顺序并补全缺失配置:

import express from 'express';
import cors from 'cors';
import { sequelize } from './Database/Models/index';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import usersRoute from './Routers/usersRoute';
import checkAuthenticated from './Middlewares/checkAuthenticated';

const app = express();

// 1. 解析JSON请求体
app.use(express.json());

// 2. 先配置CORS,处理跨域凭证
app.use(
  cors({
    origin: [
      'http://localhost:3000',
      'https://localhost:3000'
    ],
    credentials: true,
    exposedHeaders: ['set-cookie']
  })
);

app.use(cookieParser())
const SequelizeStore = require("connect-session-sequelize")(session.Store);
var myStore = new SequelizeStore({
  db: sequelize,
  checkExpirationInterval: 15 * 60 * 1000, 
  expiration: 24 * 60 * 60 * 1000  
});

// 3. 配置session并关联Store
app.use(
  session({
    secret: 'your-strong-secret-key', // 建议用环境变量存储随机密钥
    cookie: {
      secure: false, // 生产环境HTTPS下需设为true
      sameSite: 'lax', // 跨域场景确保Cookie被携带,HTTPS跨域可设为'none'
      maxAge: 24 * 60 * 60 * 1000 // 和会话过期时间保持一致
    },
    saveUninitialized: false,
    resave: false,
    unset: 'destroy',
    store: myStore // 关联SequelizeStore
  }),
);

myStore.sync();

// 挂载路由
app.use('/users', usersRoute);

2. 修复认证中间件逻辑

避免重复发送响应:

const checkAuthenticated = (req: any, res: any, next: any) => {
  if (req.session && req.session.user) {
    console.log(req.session.user)
    next(); // 认证通过,放行至后续路由
  } else {
    console.log(req.session)
    res.status(401).json({ loggedIn: false }); // 未认证返回401状态码
  }
};

export default checkAuthenticated;

3. 登录接口手动保存会话

确保会话数据立即写入数据库:

export const loginUser = async (req: any, res: any) => {
  try {
    const { error, value } = loginSchema.validate(req.body);
    if (error) {
      return res.status(400).json({ error: error.details[0].message });
    }
    const user = await serviceLoginUser(value);

    req.session.user = {
      id: user.id,
      email: user.email,
    };
    
    // 手动保存会话,确保数据持久化
    await new Promise((resolve, reject) => {
      req.session.save((err) => {
        if (err) reject(err);
        else resolve(true);
      });
    });

    res.status(200).json({Login: true, user: req.session.user});
  } catch (error: any) {
    const statusCode = error.code || 500;
    console.log(error.message)
    res.status(statusCode).json({ error: error.message });
  }
}

4. Nuxt.js Axios全局配置(可选)

在nuxt.config.ts中统一配置,避免组件内重复设置:

export default defineNuxtConfig({
  modules: ['@nuxtjs/axios'],
  axios: {
    baseURL: 'http://localhost:4000',
    credentials: true
  }
})

内容的提问来源于stack exchange,提问作者Abod Craft

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:42:03