并发请求到node.js,connect-mongo,会话被覆盖

在当前的一个项目(一种商店系统)中,我使用了expressJSconnect-mongo作为会话存储的node.js。 在客户端,我在启动时使用单个请求来创build一个新的会话,然后将多个并行请求发送到node.js服务器。 由于这些并行请求会改变会话,所以这些改变似乎会相互覆盖,当然这些改变会改变会话的不同对象。

示例(全部3个请求同时开始):

  • 请求A将一些产品推送到数组req.session.productHist['abc']
  • 请求B将产品推送到req.session.productHist['def']
  • 请求C需要一些时间,但不会改变会话

由于请求C在请求A和B之后完成,但是在完成之前开始,所以似乎用请求C开始时所保持的值覆盖session.productHist (null)。

我怎样才能解决这个问题?

更新:

控制台输出的一些示例代码:

 var url = require('url'), express = require('express'), MongoStore = require('connect-mongo'); var aDay = 24*60*60*1000; var app = express.createServer(); app.configure(function(){ app.use(express.cookieParser()); app.use(express.session({ secret: "secret", store: new MongoStore({ db: 'lmsCache' }), maxAge: aDay }) ); app.use(express.methodOverride()); app.use(express.bodyParser()); app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); app.use(app.router); app.use(express.logger()); }); function sendStringified(req, res, data) { data = JSON.stringify(data); if (req.url_query.callback) { data = req.url_query.callback + "(" + data + ");"; } res.send(data); } function parseParams(req,res,next) { req.url_query = url.parse(req.url,true).query; next(); } function doExpensiveStuff(req,res,next) { console.log("######################### init start"); [...] } app.get('/init', parseParams, doExpensiveStuff, function(req,res) { console.log("init: session.productHist: " + JSON.stringify(req.session.productHist)); console.log("######################### init end"); sendStringified(req,res,null); }); app.get('/products', parseParams, function(req,res) { console.log("######################### products "+req.url_query.category+" start"); if(!req.session.productHist[req.url_query.category]) req.session.productHist[req.url_query.category] = []; for(var i=0;i<2;i++) { req.session.productHist[req.url_query.category].push({ "id": new Date().toGMTString() }); } console.log("products: session.productHist: " + JSON.stringify(req.session.productHist)); console.log("######################### products "+req.url_query.category+" end"); sendStringified(req,res,[]); }); app.get('/newSession', parseParams, function(req,res) { console.log("######################### newSession"); req.session.productHist = {}; sendStringified(req,res,true); }); app.listen(8080); time = new Date().toGMTString(); console.log('Server starting at: ' + time); 

控制台日志:

服务器开始于:星期四,15十二月2011 15:50:37 GMT

################### newSession
################### init start
###################产品-1开始

产品:session.productHist:{“-1”:[{“id”:“Thu,15 Dec 2011 15:50:40 GMT”},{“id”:“Thu,15 Dec 2011 15:50:40 GMT “}]}

###################产品-1结束

init:session.productHist:{}

################### init结束

[…]

###################产品-1开始

产品:session.productHist:{“-1”:[{“id”:“Thu,15 Dec 2011 15:50:53 GMT”},{“id”:“Thu,15 Dec 2011 15:50:53 GMT “}]}

###################产品-1结束

我想我已经find了这个棘手问题的答案。

从Express.js文档:

Properties on req.session are automatically saved on a response

简洁版本

当你设置一个会话variables( req.session.my_var = value )时,实际上并没有保存(在那个时刻),但是后来(当你发送响应的时候,在你的情况下是res.send )。 这导致了你的问题。

长版

那么究竟是什么意思?

  1. 你提出一个请求,然后得到会话variables(这是在状态A),然后做一些事情(这需要一些时间)
  2. 你做了另一个请求,并获得会话variables(仍然处于状态A,因为响应尚未发送),并改变一些东西
  3. 现在会话处理等已经完成,所以你发送1)的响应,从而修改会话variables,并将其带入状态B.
  4. 在你发送了2)的回应之后,“快乐”的部分就来了。 现在你实际上并没有修改当前会话(已经更新到状态B),因为响应被延迟了,所以你实际上正在改变的是来自状态A的会话,使它进入状态C =>这意味着所有状态B的修改丢失了!