草庐IT

session - 对 node.js、connect-mongo、 session 覆盖的并行请求

coder 2023-05-05 原文

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

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

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

因为请求 C 在请求 A 和 B 之后完成,但在它们完成之前开始,所以它似乎用请求 C 开始时保持的值(null)覆盖了 session.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);  

控制台日志:

Server starting at: Thu, 15 Dec 2011 15:50:37 GMT

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

products: session.productHist: {"-1":[{"id":"Thu, 15 Dec 2011 15:50:40 GMT"},{"id":"Thu, 15 Dec 2011 15:50:40 GMT"}]}

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


init: session.productHist: {}

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


[...]

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

products: session.productHist: {"-1":[{"id":"Thu, 15 Dec 2011 15:50:53 GMT"},{"id":"Thu, 15 Dec 2011 15:50:53 GMT"}]}

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

最佳答案

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

来自 Express.js文档:

req.session 上的属性会自动保存在响应中

短版

当您设置 session 变量 (req.session.my_var = value) 时,它实际上并没有被保存(当时),而是稍后(当您发送响应时,在您的情况下)当你执行 res.send 时)。这导致了你的问题。

加长版

那么这到底是什么意思?

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

关于session - 对 node.js、connect-mongo、 session 覆盖的并行请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8507278/

有关session - 对 node.js、connect-mongo、 session 覆盖的并行请求的更多相关文章

  1. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  4. ruby - 覆盖相似的方法,更短的语法 - 2

    在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a

  5. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  6. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  7. ruby-on-rails - Rails 优雅地处理超时 session ? - 2

    使用rails4,ruby2。我在rails配置中为我的cookiesession设置了30分钟的超时时间。问题是,如果我转到表单,让session超时,然后提交表单,我会收到此ActionController::InvalidAuthenticityToken错误。如何在Rails中优雅地处理这个错误?比如说,重定向到登录屏幕? 最佳答案 在您的ApplicationController:rescue_fromActionController::InvalidAuthenticityTokendoredirect_tosome_p

  8. ruby - 带括号和 splat 运算符的并行赋值 - 2

    我明白了:x,(y,z)=1,*[2,3]x#=>1y#=>2z#=>nil我想知道为什么z的值为nil。 最佳答案 x,(y,z)=1,*[2,3]右侧的splat*是内联扩展的,所以它等同于:x,(y,z)=1,2,3左边带括号的列表被视为嵌套赋值,所以它等价于:x=1y,z=23被丢弃,而z被分配给nil。 关于ruby-带括号和splat运算符的并行赋值,我们在StackOverflow上找到一个类似的问题: https://stackoverflow

  9. ruby-on-rails - 为什么在 Rails 5.1.1 中删除了 session 存储初始化程序 - 2

    我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于

  10. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

随机推荐