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

时间:2011-12-14 15:40:19

标签: session mongodb node.js parallel-processing express

在当前项目(一种商店系统)中,我将node.js与 expressJS connect-mongo 一起用作会话存储。在客户端,我在启动时使用单个请求来创建新会话,然后向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);  

控制台日志:

  

服务器起始于:2011年12月15日星期四15:50:37 GMT

     ################### newSession
     ################### init start      ################### products -1 start      

产品:session.productHist:{“ - 1”:[{“id”:“星期四,2011年12月15日15:50:40 GMT”},{“id”:“星期四,2011年12月15日15:50 :40 GMT“}]}

     ################### products -1 end      


  init:session.productHist:{}

     ################### init end      


  [...]

     ################### products -1 start      

产品:session.productHist:{“ - 1”:[{“id”:“星期四,2011年12月15日15:50:53 GMT”},{“id”:“星期四,2011年12月15日15:50 :53 GMT“}]}

     ################### products -1 end

1 个答案:

答案 0 :(得分:3)

我想我找到了这个棘手问题的答案。

来自Express.js文档:

Properties on req.session are automatically saved on a response

简短版

当您设置会话变量(req.session.my_var = value)时,它实际上并未保存(在那个确切的时刻),但稍后(当您发送响应时,在您的情况下,当您执行res.send时)。这导致了你的问题。

长版

那究竟是什么意思?

  1. 您发出请求,然后获取会话变量(处于状态A),然后执行该操作(需要一些时间)
  2. 您发出另一个请求并获取会话变量(仍处于状态A,因为尚未发送响应)并更改了一些内容
  3. 现在已完成会话处理等,因此您从1)发送响应,从而修改会话变量并将其置于状态B
  4. 从2)发送回复后,这里出现了“有趣”部分。现在你实际上并没有修改当前会话(已经更新到状态B),因为响应被延迟了,所以你实际改变的是来自状态A的会话,使其进入状态C =&gt;这意味着B州的所有修改都丢失了!