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

Express-session购物车每次请求后session.cart丢失问题求助

问题:Express-session购物车在浏览器请求中始终重置,Postman测试正常

使用Express.js搭配Handlebars开发网站,采用express-session存储购物车信息。遇到如下问题:每次在浏览器中发起添加商品到购物车的请求时,req.session.cart始终为undefined,导致每次都会创建新的购物车,仅能添加一件商品;但在Postman中测试时功能完全正常。


相关代码

cartController.js

const {add, initCart, cartDetail} = require('../../services/cartService')

const getCart = async(req, res)=>{
  console.log('get cart',req.session)
  console.log(req.session.cart)
  console.log(req.session.test)
  res.json(await cartDetail(req.session.cart));
}

const addItemToCart = (req, res)=>{
  console.log('Vao add to cart ')
  console.log(req.body)

  const {productId} = req.body;
  req.session.test = 'test';
  if(req.session.cart){
    console.log('da co cart')
  }
  if(!req.session.cart){
    req.session.cart = initCart();
  } 

  console.log(' before add item to cart',req.session)
  add(productId, req.session.cart)
  console.log(req.session.cart)
  console.log(' after add item to cart',req.session)
  res.json(req.session.cart)

}

module.exports = {
  getCart,
  addItemToCart
}

cartService.js

const {getSpecificProductById}= require('./productService')

exports.add = (productId, cart)=>{
  const foundProduct = cart.products.find(product=>product.id === productId);
  if(foundProduct){
    foundProduct.quantity = foundProduct.quantity+1;
  }else{
    cart.products.push({id: productId, quantity: 1});
  }
}

exports.cartDetail = async(cart)=>{
  const cartDetails = {...cart};
  cartDetails.products  = await Promise.all(cartDetails.products.map(async product=>{
    const productInfo = await getSpecificProductById(product.id);
    return {
      ...product,
      name: productInfo.name,
      price: productInfo.price,
      image: productInfo.image,
    }
  }))

  return cartDetails;
}

exports.initCart = ()=>(
  {
    products: []
  }
)

app.js

const hbs  = require('hbs')
var indexRouter = require("./routes/home");
var usersRouter = require("./routes/users");
const {aboutRouter} = require("./routes/aboutRouter")
const {shoppingCartRouter} = require("./routes/shoppingCartRouter")
const {checkoutRouter} = require("./routes/checkoutRouter")
const productRouter = require('./routes/productRouter')
const authRouter = require("./auth/authRouter");
const profileRouter = require("./routes/profileRouter")
const authApiRouter = require('./auth/api')
const productApiRouter = require('./routes/APIRoutes/productApiRouter');
const cartApiRouter = require('./routes/APIRoutes/cartApiRouter');

const session = require("express-session");
const passport = require('./auth/passport/index')

const MySQLStore = require('connect-mysql')(session)
const options = {
  config:{
    host:'localhost',
    user:'root',
    password: '280502',
    database: 'session-db'
  }
}

const paginate = require('express-paginate')

const cors = require('cors')


var app = express();

// view engine setup

app.use(cors())
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
hbs.registerPartials(__dirname + '/views/partials');
hbs.handlebars.registerHelper("minus", (a,b)=>{
  return a-b
})
var blocks = {};

hbs.handlebars.registerHelper('extend', function(name, context) {
  var block = blocks[name];
  if (!block) {
    block = blocks[name] = [];
  }

  block.push(context.fn(this)); // for older versions of handlebars, use block.push(context(this));
});

hbs.handlebars.registerHelper('block', function(name) {
  var val = (blocks[name] || []).join('\n');

  // clear the block
  blocks[name] = [];
  return val;
});

app.use(paginate.middleware(5, 20))
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use(session({
  secret: 'very secret keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: {
    httpOnly: false, 
    secure: false,
    maxAge: 1000 * 60 * 60 * 24 * 3,
    expires: 1000 * 60 * 60 * 24 * 3,
  },
  store: new MySQLStore(options)
}))
app.use(passport.authenticate('session'));
app.use((req,res,next)=>{
  res.locals.user = req.user
  next();
});

app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/about", aboutRouter);
app.use("/products", productRouter)
app.use("/api/products", productApiRouter)
app.use("/auth", authRouter);

//api
app.use('/api/auth',authApiRouter);
app.use("/cart", shoppingCartRouter)

app.use("/api/cart", cartApiRouter);
app.use("/checkout", checkoutRouter)
app.use("/profile", profileRouter)

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});

module.exports = app;

可能的原因及解决方法

Postman会自动保存并发送Cookie,但浏览器在Ajax请求中默认不会携带Cookie,需手动配置:

  • 若使用fetch:
    fetch('/api/cart/add', {
      method: 'POST',
      credentials: 'include', // 跨域时用include,同域可用same-origin
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({ productId: 'xxx' })
    })
    
  • 若使用Axios:
    axios.post('/api/cart/add', { productId: 'xxx' }, { withCredentials: true })
    

2. Session Cookie配置优化

当前配置中httpOnly: false存在安全风险,且expires与maxAge同时设置可能冲突,建议调整:

cookie: {
  httpOnly: true, // 禁止前端读取Cookie,提升安全性
  secure: process.env.NODE_ENV === 'production', // 生产环境开启HTTPS时启用
  maxAge: 1000 * 60 * 60 * 24 * 3 // 仅保留maxAge即可
}

3. 检查Session存储有效性

确认connect-mysql已正确创建session表,MySQL连接正常。可直接查看数据库中的session表,验证每次请求后session数据是否被正确保存。

4. 调试建议

  • 在浏览器开发者工具的Application标签下,查看是否存在connect.sid(默认session Cookie名),且每次请求都会携带该Cookie;
  • 在addItemToCart中打印req.headers.cookie,确认请求是否携带session标识;
  • 检查MySQL的session表,确认每次请求后session记录是否更新。

内容的提问来源于stack exchange,提问作者Khải Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:01:04