Session 对node.js、connect mongo、会话覆盖的并行请求

Session 对node.js、connect mongo、会话覆盖的并行请求,session,mongodb,node.js,parallel-processing,express,Session,Mongodb,Node.js,Parallel Processing,Express,在当前项目(车间系统的类型)中,我使用node.js withexpressJS和connectmongo作为会话存储。在客户端,我在启动时使用一个请求创建一个新会话,然后将多个并行请求发送到node.js服务器。 因为这些并行请求会更改会话,所以这些更改似乎会相互覆盖,当然,它们会更改会话的不同对象 示例(所有3个请求同时启动): 请求A将一些产品推送到数组req.session.productHist['abc'] 请求B将产品推送到req.session.productHist['def

在当前项目(车间系统的类型)中,我使用node.js withexpressJSconnectmongo作为会话存储。在客户端,我在启动时使用一个请求创建一个新会话,然后将多个并行请求发送到node.js服务器。 因为这些并行请求会更改会话,所以这些更改似乎会相互覆盖,当然,它们会更改会话的不同对象

示例(所有3个请求同时启动):

  • 请求A将一些产品推送到数组
    req.session.productHist['abc']
  • 请求B将产品推送到
    req.session.productHist['def']
  • 请求C需要一些时间,但不会更改会话
由于请求C在请求A和B之后完成,但在它们完成之前启动,因此它似乎用请求C启动时保留的值(null)覆盖了会话.productHist

我怎样才能解决这个问题

更新:

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

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);  
var url=require('url'),
express=require('express'),
MongoStore=require('connect-mongo');
日变化率=24*60*60*1000;
var app=express.createServer();
app.configure(函数(){
use(express.cookieParser());
应用程序使用(express.session)({
秘密:“秘密”,
商店:新蒙哥斯托尔({db:'lmsCache'}),
maxAge:aDay
})
);
app.use(express.methodOverride());app.use(express.bodyParser());
use(express.errorHandler({dumpExceptions:true,showStack:true}));
应用程序使用(应用程序路由器);
app.use(express.logger());
});
函数sendStringified(请求、恢复、数据){
data=JSON.stringify(数据);
if(req.url_query.callback){data=req.url_query.callback+“(“+data+”);”}
res.send(数据);
}
函数解析参数(req、res、next){
req.url\u query=url.parse(req.url,true).query;
next();
}
函数doExpensiveStuff(req、res、next){
控制台。日志(“开始时”);
[...]
}
app.get('/init',parseParams,doExpensiveStuff,function(req,res){
log(“init:session.productHist:+JSON.stringify(req.session.productHist));
控制台。日志(“首端”);
sendStringified(请求、回复、空);
});
app.get('/products',parseParams,function(req,res){
console.log(“###############################################产品”+;
if(!req.session.productHist[req.url\u query.category])
req.session.productHist[req.url\u query.category]=[];

对于(var i=0;i我想我已经找到了这个棘手问题的答案

从文件中:

请求会话上的属性将自动保存在响应中

短版

当您设置一个会话变量(
req.session.my_var=value
)时,它实际上不会在当时保存,而是在以后保存(当您发送响应时,在您的情况下是在您执行
res.send
)时。这导致了您的问题

长版本

那么这到底意味着什么呢

  • 您发出请求,然后获取会话变量(处于状态a),然后对其进行处理(这需要一些时间)
  • 您发出另一个请求并获取会话变量(由于响应尚未发送,因此仍处于状态A),然后对其进行一些更改
  • 现在,会话处理etc已经完成,因此您可以从1)发送响应,从而修改会话变量并使其进入状态B
  • 在您发送了来自2的响应之后,这里是“有趣”部分。现在您实际上没有修改当前会话(已更新为状态B),因为响应被延迟,所以您实际更改的是来自状态A的会话,将其带到状态C=>这意味着来自状态B的所有修改都丢失了

  • 请求C不能在A&B之后发生吗?如果可能的话,我希望能够以某种方式发送并行请求。我可以在C完成后发送A&B,但这会减慢用户体验请求C到底做了什么..?请求C返回初始化数据,如用户数据、要显示的类别等。请求A和B返回具有不同参数的产品ters(来自不同类别)并且应该将它们添加到产品历史记录中,这样它们就不会在以后的请求中再次显示。你肯定是做错了什么。例如,如果你推到一个数组,或者在req.session上定义了一个不同的属性,它就不应该被覆盖。我想这就是问题所在,但是你有解决方案吗?我想我可以镜像整个se在node.js内存中使用session,但我认为这不是一个好的解决方案,因为它会使mongo存储在某一点上变得不必要(并造成很大的开销)。我想知道是否有现成的解决方案,因为我肯定不是第一个遇到这个问题的人。这不一定是一个完美的解决方案,但最好先进行处理,然后调用
    req.sessionStore.reload(回调函数)
    并在回调函数中更改会话并立即调用
    res.send
    。最好的解决方案是拥有一个通信通道(UNIX套接字、Redis),并在更改会话时发送通知(从而模拟锁定,例如消息:“session:id locked”)当您发送响应以触发另一条消息(“会话:id unlocked”)时。每个请求都应该在侦听,并且在锁定时(在“unlocked”重新加载会话上)不会修改会话。感谢您的帮助:)我会尝试一下,直到找到更好的解决方案(如果我找到了)。