前面的 Part 3 講了預設的 Session,現在來提一下 MongoDB 與 Redis 的儲存方式,篇幅夠的話,順便會提到 Cookie base 的儲存方法。
Session in MongoDB
在 Express 當中,Session 預設儲存的方式是記憶體。如果你要儲存在資料庫中也是可以的,關於資料庫呢,這邊除了 MongoDB 之外,還有另外一個,叫做 Redis。他與 MongoDB 一樣是 key/value 的資料庫。差別大概在他有 VMware sponsored 這樣吧(喂
由於先前我們已經介紹過 MongoDB,所以這邊先以 MongoDB 的儲存方式來介紹。雖然 Connect 推薦使用 Redis 來作儲存媒介,不過也沒硬性規定就是。
BUT!
原生的寫法是行不通的,
(function() {
var app, express, mongo, mongoServer;
express = require('express');
mongo = require('mongodb');
mongoServer = new mongo.Server('localhost', 27017, {
auto_reconnect: true,
pooSize: 5
});
/home/hinablue/workspace/works/jsdc/
app = express.createServer();
app.configure(function() {
this.use(express.cookieParser());
return this.use(express.session({
secret: "@#$TYHBVGHJIY^TWEYKJHNBGFDWGHJKUYTWE#$%^&*&^%$#",
store: new mongo.Db('mysession', mongoServer)
}));
});
app.get("/", function(req, res) {
console.info(req.session.item);
req.session.item = 'Hello World';
return res.send('Hello World');
});
app.listen(3000, function() {
return console.info("Express server listening on port " + (this.address().port) + " in " + process.env.NODE_ENV + " mode");
});
}).call(this);
馬上就會出現錯誤,
$ node test.js
Express server listening on port 3000 in development mode
TypeError: Object #<Db> has no method 'get'
at Object.session [as handle] (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/middleware/session.js:318:11)
at next (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/http.js:203:15)
at Object.cookieParser [as handle] (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js:44:5)
at next (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/http.js:203:15)
at Object.handle (/home/hinablue/node-in-session/node_modules/express/lib/http.js:83:5)
at next (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/http.js:203:15)
at HTTPServer.handle (/home/hinablue/node-in-session/node_modules/express/node_modules/connect/lib/http.js:216:3)
at HTTPServer.emit (events.js:70:17)
at HTTPParser.onIncoming (http.js:1514:12)
at HTTPParser.onHeadersComplete (http.js:102:31)
不要問我為什麼,這個問題是 mongodb-native 中的動作,跟 Connect 中的作法不同所導致。所以,請使用 connect-mongo,
(function() {
var app, express, mongoStore;
express = require('express');
mongoStore = require('connect-mongo')(express);
app = express.createServer();
app.configure(function() {
this.use(express.cookieParser());
return this.use(express.session({
secret: "@#$TYHBVGHJIY^TWEYKJHNBGFDWGHJKUYTWE#$%^&*&^%$#",
store: new mongoStore({
host: 'localhost',
port: 27017,
db: 'mysessions',
collection: 'sessions'
})
}));
});
app.get("/", function(req, res) {
console.info(req.session.item);
req.session.item = 'Hello World';
return res.send('Hello World');
});
app.listen(3000, function() {
return console.info("Express server listening on port " + (this.address().port) + " in " + process.env.NODE_ENV + " mode");
});
}).call(this);
然後我們從 console 進去 mongo 查看一下,
$ mongo
MongoDB shell version: 2.0.4
connecting to: test
> show dbs
local (empty)
mysessions 0.203125GB
> use mysessions
switched to db mysessions
> show collections
sessions
system.indexes
> db.sessions.find()
{ "_id" : "vB4Gd1rZJQ8e6s0rbE0rEqrR.c0VnxIUGAxsQfi9zA2XoQ9lV9oIs5ULsn+Y/99wu1pI", "session" : "{\"lastAccess\":1334752463452,\"cookie\":{\"originalMaxAge\":14400000,\"expires\":\"2012-04-18T16:34:23.452Z\",\"httpOnly\":true,\"path\":\"/\"},\"item\":\"Hello World\"}", "expires" : ISODate("2012-04-18T16:34:23.452Z") }
>
這樣你就看到我們剛剛存的東西了。
Session in Redis
另外就是 Redis 了,首先要安裝,
$ sudo apt-get install redis-server
然後我們改寫一下,
(function() {
var app, express, redisStore;
express = require('express');
redisStore = require('connect-redis')(express);
app = express.createServer();
app.configure(function() {
this.use(express.cookieParser());
return this.use(express.session({
secret: "@#$TYHBVGHJIY^TWEYKJHNBGFDWGHJKUYTWE#$%^&*&^%$#",
store: new redisStore()
}));
});
app.get("/", function(req, res) {
console.info(req.session.item);
req.session.item = 'Hello World';
return res.send('Hello World');
});
app.listen(3000, function() {
return console.info("Express server listening on port " + (this.address().port) + " in " + process.env.NODE_ENV + " mode");
});
}).call(this);
然後用瀏覽器跑一下,我們再用 redis-cli 來看看儲存的結果,
$ node test.js
Express server listening on port 3000 in development mode
undefined
Hello World
$ redis-cli
redis 127.0.0.1:6379> KEYS *
1) "sess:8nQiHfxTHfouhSaB5tgj1cQY.UP0VLd1qOneh0D30H2+ivDyYLlX/GcXLdIl9dczWAlg"
redis 127.0.0.1:6379> MGET "sess:8nQiHfxTHfouhSaB5tgj1cQY.UP0VLd1qOneh0D30H2+ivDyYLlX/GcXLdIl9dczWAlg"
1) "{\"lastAccess\":1334753540196,\"cookie\":{\"originalMaxAge\":14400000,\"expires\":\"2012-04-18T16:52:20.197Z\",\"httpOnly\":true,\"path\":\"/\"},\"item\":\"Hello World\"}"
redis 127.0.0.1:6379> exit
這樣就會發現,我們剛剛所儲存的 Session 了!
Session in Cookie
最後我們來說一下 Cookie base 的儲存方式。這個儲存方式有 Cookie 先天的限制,所以,如果你的 Session 所儲存的內容過多(大於 4kb),或是你有些敏感的資料的話,是不建議使用這種方式來儲存的。
(function() {
var app, connect, express;
connect = require('connect');
express = require('express');
app = express.createServer();
app.configure(function() {
this.use(express.cookieParser('@#$TYHBVGHJIY^TWEYKJHNBGFDWGHJKUYTWE#$%^&*&^%$#'));
return this.use(express.cookieSession());
});
app.get("/", function(req, res) {
console.info(req.session.item);
req.session.item = 'Hello World';
return res.send('Hello World');
});
app.get("/page2", function(req, res) {
console.log(req.session.item);
return res.send(req.session.item);
});
app.listen(5000, function() {
return console.info("Express server listening on port " + (this.address().port) + " in mode");
});
}).call(this);
執行結果呢?
$ node test.js
Express server listening on port 3000 in development mode
Hello World
Hello World
你會發現,我一打開瀏覽器就會出現 Session 的資料了,為什麼?因為這是用 Cookie 儲存的關係,所以不要問我為什麼。另外,注意! express.cookieParser() 裡面的 secret 一定要寫,不然會錯誤喔!
我這裡貼上 Header 的結果給大家參考一下,
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:connect.sid=dj5sq4si22fODOemcEpTrGzT.h%2BHj4JNtvtQpJp%2BA6pUdh1xiEzTv0hoZH%2BLy%2FKr9%2F1g; connect.sess=j%3A%7B%22item%22%3A%22Hello%20World%2C%20asdjfkla%3Bdfja%3Blskdfja%3Bsldkfja%3Bsldfjas%3Bldfja%3Bsldfkjas%3Bldfja%3Bsldfjka%3Bdlfja%3Bsldfjka%3Bsldfja%3Bldkjfa%3Bsldfj%22%7D.41ZpYhK3SpKO5CxWXwa1eJlODvp%2Fj1%2BE9a0dbFL9emk
Host:localhost:5000
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.24 Safari/536.5
請注意 Cookie 的部份,這個部份有 connect.sess 這是 Connect 預設的,裡面是加密過的資料,當你所儲存的 Session 越多時,這個東西就會越來越長。如果過長會炸掉,就這樣!
結語
Session 還是用 DB 來存會好一點,就這樣啦(飄走