NodeJS Express中无法获取到存储到session中的值

Express是一个NodeJS的Web框架,类似rails是ruby的web框架。关于Express这里不多介绍,这几天使用Express的session功能的时候时,遇到一个session属性丢失的问题,在这里分享一些经验。

我们首先看Express中session的官方的sample code

// first:
// $ npm install redis
// $ redis-server

var express = require('../..');

var app = express();

app.use(express.logger('dev'));

// Required by session() middleware
// pass the secret for signed cookies
// (required by session())
app.use(express.cookieParser('keyboard cat'));

// Populates req.session
app.use(express.session());

app.get('/', function(req, res){
var body = '';
if (req.session.views) {
++req.session.views;
res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
} else {
req.session.views = 1;
body += '<p>First time visiting? view this page in several browsers :)</p>';
res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
}
});

app.listen(3000);
console.log('Express app started on port 3000');
在运行之前,需要了解几点:

  1. 草绿色的两行代码是必须的,keyboard cat’是用来加密cookie的密钥。
  2. session需要介质存储存储,express.session()的方式默认存储在内存中。还有一种常用的方法是存储在数据库中,redis是一个Non-SQL的数据库,有NodeJS的插件可以访问他,redis是常用的。不过考虑到太重量了,我没有用。而是存储在内存中。
  3. session提供了regenerate方法,用来将整个session清空,然后可以重新赋值。

我遇到的问题是,在登录请求中,使用session的 regenerate方法创建一个全新的session:

function login(request, response){

request.session.regenerate( function(){
request.session.username = userInfo.username;
console.log("set session username = " + request.session.username);
console.log(request);
response.write(JSON.stringify(loginResult));
response.end();
} );
}

然后,在登录后的其他请求中,判断request.session.username是否存在,但是获取不到,request.session.username is undefined.

这个问题困扰了我3个早上,我排查了各种可能:

  1. 我不清楚session存在内存中是否有问题,那时候我还没有跑Express session的官方sample,后来在官方sample的代码中,我得知这个是不会有问题的。在这之前,我尝试过使用redis去存储session,后来我认为使用数据库太重量了不可接受接,所以放弃了。
  2. 我怀疑过是否是query的ajax请求方式没有将session中的cookie传递到后台,通过谷歌(感谢谷歌)我发现了cookie属性path,如果设置为了/,那么所有请求都会发送这个cookie,通过抓包也看到了有cookie。
  3. 由于client有发送,但是服务端没有接收到,我的逻辑中有请求跳转,是否是跳转后session被重置了?我就开始观察每个请求的session,通过打印出每个请求的session信息,终于观察到了,每次登录后,都是一个空的session将之前产生的session覆盖了:

sessionStore:
{ sessions:
{ 'c+bFzYy2z23b8b3Wa+fV6nCO': '{"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"}}',
fk8DJoqGwOyrQ4jiFfWu4hry: '{"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"},"username":"Lucy"}',
'sJJycHWSy+JANARqVUw4Jhl0': '{"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"}}',

  1. 那么可以肯定是请求哪里出问题了,session被覆盖了。通过搜索,发现有一个说法是Express框架中的请求favicon功能导致的,需要通过增加app.use(express.favicon());代码来解决。我尝试了,可是还是不行。
  2. 我对request.session.regenerate( function(){方法一直没有底,于是不重新构造session,直接赋值,发现问题解决了。
  3. 后来我将app.use(express.favicon());删除之后,还是没问题,这个就比较奇怪了,因为我最开始就有尝试过不使用request.session.regenerate( function(){,但是没生效。但是我认为是缓存的问题,因为浏览器上的favicon自从我使用了app.use(express.favicon());代码之后,就一直没有换过,说明没有去重新更新favicon。
  4. 但是我在sample代码中增加了request.session.regenerate( function(){方法,也没有使用app.use(express.favicon());方法,但是也不会有问题。我怀疑是类似多线程问题,如果请求多一些,可能会有问题。

这个问题,我最终的建议是:使用app.use(express.favicon());方法,给session赋值的时候,不要使用request.session.regenerate( function(){方法重建session。

转载请注明:运维派 » NodeJS Express中无法获取到存储到session中的值

0
5.7k
2
  1. 我记得默认是session是去掉favicon的,我不知道你使用的版本是不是比较旧,有函数是可以指定哪些不需要通过session,比如icon这种就没必要请求是检查是否有登陆,你需要在网上找一下。

  2. 我使用的是通过express-generator创建的app,我的方法是在app.use(‘/’, routes);的前面添加app.use(function(req, res, next) { res.locals.user = req.session.user; next();});在每次请求中同步服务端和客户端的session的user。可以参考下