Node.js + Express.js:使用MongoDB/Mongoose处理会话管理

39

现在,我将我的会话数据存储在 connect(express) 自带的“内存存储”中。但是我想/必须为生产环境更改这个设置。

该应用程序正在使用mongodb,我已经安装了mongoose来处理所有的数据库通信。

例如,在初始化我的应用程序后连接到数据库:

var mongo = require('mongoose');
mongo.connect('mongodb://localhost/myDb');
mongo.connection.on('open', function () {
  app.listen(3000);
}

我找到了 connect-mongodb 模块,但我不知道如何在 mongoose 中实现它,或者它是否真的可行?我需要添加类似于以下的内容:

var mongoStore = require('connect-mongodb');
// ...
app.use(express.session({
  secret: 'topsecret',
  maxAge: new Date(Date.now() + 3600000),
  store: new mongoStore({ db: 'myDb' })
}));

还是说我必须直接使用mongodb模块重新定义我的数据库连接?

7个回答

43
  • 最终我使用了之前所有答案中提到的方法:
  • 我从connect-mongodb切换到了connect-mongo模块
  • 我正在使用一个常规配置对象来存储我的配置数据
  • 有两个数据库连接,因为这对我来说更容易处理(如果/当mongoose / express的新版本发布时可能会改变)

要求:

var express = require('express'),
    MongoStore = require('connect-mongo')(express),
    mongo = require('mongoose');

配置对象:

var conf = {
  db: {
    db: 'myDb',
    host: '192.168.1.111',
    port: 6646,  // optional, default: 27017
    username: 'admin', // optional
    password: 'secret', // optional
    collection: 'mySessions' // optional, default: sessions
  },
  secret: '076ee61d63aa10a125ea872411e433b9'
};

那我可以像这样配置它:

app.configure(function(){
  // ...
  app.use(express.cookieParser());
  app.use(express.session({
    secret: conf.secret,
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(conf.db)
  }));
  // important that this comes after session management
  app.use(app.router);
  // ...
});

最后使用mongoose第二次连接mongodb:

var dbUrl = 'mongodb://';
dbUrl += conf.db.username + ':' + conf.db.password + '@';
dbUrl += conf.db.host + ':' + conf.db.port;
dbUrl += '/' + conf.db.db;
mongo.connect(dbUrl);
mongo.connection.on('open', function () {
  app.listen(3000);
});

干得好!我唯一要补充的是,确保你的“app.use(app.router);”放在“app.use(express.session...)”之后,这样可以避免问题的复杂化。 - Salida Software
9
最近想让这个工作起来的人需要注意:从v0.1.9开始,您需要将express设置为一个变量(var express = require('express')),然后将其传递给connect-mongo(var MongoStore = require('connect-mongo')(express))。这是因为express公开了connect的所有基础部分,而connect-mongo实际上是一个以connect对象作为参数的函数。 - Peter Downs
为了避免 EADDRINUSE 错误,我不得不从您的代码底部删除了 "app.listen(3000)" 行,因为我已经在其他地方进行了 .listen。那部分只需要执行一次,是用于启动实际的 express web 服务器本身 - 并不是与 mongodb 连接相关的。只是一条注释! - CommaToast
好的,我到这里了,但是现在我该如何与会话交互?设置和获取值... - Hadesara
@Hadesara 这里有关于expressjs和sessions的优秀文档:http://expressjs-book.com/forums/topic/express-js-sessions-a-detailed-tutorial - ngChris
嗨,我正在尝试自己理解express-session,但在将会话存储在mongoDB中时遇到了问题 - 您觉得可以看一下这里吗:http://stackoverflow.com/questions/32413051/express-js-multiple-temp-sessions-for-same-domain-in-mongodb?谢谢! - Kawd

27
请包含。
app.use(express.cookieParser());

直接在之前

app.use(express.session({

否则会抛出以下错误:

TypeError: Cannot read property 'connect.sid' of undefined


3
救了生命。互联网上的信息是错误的——甚至在搜索结果的前几页中都没有任何一个例子提到过这个。 - antitoxic
3
谢谢你的提示,但下次可以直接编辑我的答案并添加缺失的内容,这样其他人就不必阅读另一个答案了... - Philipp Kyeck

7

看起来您可以这样设置connect-mongodb,假设您上面的mongoose连接代码先运行:

app.use(express.session({
  secret: 'topsecret',
  maxAge: new Date(Date.now() + 3600000),
  store: new mongoStore({ db: mongoose.connections[0].db })
}));

我正在使用express.session()在连接数据库之前的app.configure()中。我认为,我会定义一个包含所有DB信息的config对象,并尝试使用connect-mongo(而不是connect-mongodb)-实现看起来比connect-mongodb更容易。 - Philipp Kyeck
Github页面上的示例没有说明如何与Mongoose一起使用。这个示例帮了很大的忙。 - mauris

3
所以,connect-mongodb并不使用Mongoose,而是使用node-mongodb-native驱动程序(即:npm install mongodb)。Mongoose也依赖于这个驱动程序,所以它应该存在。
查看直接的代码,你需要将你的数据库连接信息提供为MongoStore对象:
store: new mongoStore({ host: 'session_server', port: 27017, db: 'seesion', collection: 'sessions' })

通常情况下,您需要一个“配置”对象或变量,可以动态加载(dev vs test vs prod)。然后,您从该配置对象中提取主机/端口/数据库/身份验证信息。

你链接到了connect-mongo,我在示例中使用了connect-mongodb。但它们几乎相同,所以我会检查一下。 - Philipp Kyeck

3

对于express 4x:

var express = require('express'),
    session = require('express-session'),
    MongoStore = require('connect-mongo')(session),
    mongo = require('mongoose');

var conf = {
  db: {
    db: 'myDb',
    host: '192.168.1.111',
    port: 6646,  // optional, default: 27017
    username: 'admin', // optional
    password: 'secret', // optional
    collection: 'mySessions' // optional, default: sessions
  },
  secret: '076ee61d63aa10a125ea872411e433b9'
};

app.configure(function(){
  app.use(express.cookieParser());
  app.use(session({
    secret: conf.secret,
    maxAge: new Date(Date.now() + 3600000),
    store: new MongoStore(conf.db)
  }));
});

var dbUrl = 'mongodb://';
dbUrl += conf.db.username + ':' + conf.db.password + '@';
dbUrl += conf.db.host + ':' + conf.db.port;
dbUrl += '/' + conf.db.db;
mongo.connect(dbUrl);
mongo.connection.on('open', function () {
  app.listen(3000);
});

session 已经被移动到它自己的模块中,所以你需要 require 它,并在配置 MongoStore 时使用 session


在第三行中,require语句后面的(session)是什么意思?它是否像把(session)传递给了mongoStore? - ajay_t

1

您可以传递一个包含连接细节的对象(主机、用户名、密码等)。

您也可以传递一个连接 URL,例如 mongodb://user:pass@host.com/db_name。

这两种方法都会自动启动新的连接,无论您是否已经或将要启动 mongoose 连接。

在最新的代码中,您可以传递一个现有连接的句柄,即 mongodb.Db 的实例。对于 mongoose,这将是 mongoose.connection.db。然而,这段代码并没有在实际发布中,当我尝试时,它并没有起作用。可能还没有准备好使用(或未经测试)。

我相信如果您等待下一个版本发布,就可以传递一个现有的 mongoose 连接。在此期间,您只需要接受有两个连接,一个来自 mongoose,一个来自 connect-mongodb。

我从https://github.com/tedeh/connect-mongodb获取了连接信息,而且通过查看源代码(相关提交),我得到了处理信息。


0

我刚刚偶然发现了mongoose-session

非常轻量级,对我来说无缝运行。来自github...

安装

npm install mongoose-session

使用

var express = require('express');

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/db');

var app = express();

app.use(require('express-session')({
    key: 'session',
    secret: 'SUPER SECRET SECRET',
    store: require('mongoose-session')(mongoose)
}));

2
从 repo mongoose-session已停用。请改用 connect-mongo。它更好用。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接