1. 程式人生 > >NodeJS Express中無法獲取到儲存到session中的值

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。