2012-06-05 131 views
3

我有以下路线,基本上从登录表单发布的行为。问题是,当登录成功时(找到成员并且密码匹配),member._id不会存储在会话中。会话没有存储在Express的Node.js

我的路线:

app.post('/signin', function(req, res) { 
    Member.findOne({username: req.body.username}, function(error, member) { 
     var matchPassword = crypto.createHmac('sha1', member.salt).update(req.body.password).digest('hex'); 
     if(member.password == matchPassword) { 
      req.session.member_id = member._id; 
      res.redirect('/' + member.username); 
     } 
    }); 
    res.redirect('/'); 
}); 

我得到控制台以下错误,当这条路被触发:

node.js:134 
     throw e; // process.nextTick error, or 'error' event on first tick 
     ^
Error: Can't set headers after they are sent. 
    at ServerResponse.<anonymous> (http.js:527:11) 
    at ServerResponse.setHeader (/Users/admin/Node Projects/sandboxProject/node_modules/express/node_modules/connect/lib/patch.js:62:20) 
    at ServerResponse.header (/Users/admin/Node Projects/sandboxProject/node_modules/express/lib/response.js:280:8) 
    at ServerResponse.redirect (/Users/admin/Node Projects/sandboxProject/node_modules/express/lib/response.js:413:10) 
    at Promise.<anonymous> (/Users/admin/Node Projects/sandboxProject/app.js:109:8) 
    at Promise.<anonymous> (/Users/admin/Node Projects/sandboxProject/node_modules/mongoose/lib/promise.js:120:8) 
    at Promise.<anonymous> (events.js:64:17) 
    at Promise.emit (/Users/admin/Node Projects/sandboxProject/node_modules/mongoose/lib/promise.js:59:38) 
    at Promise.complete (/Users/admin/Node Projects/sandboxProject/node_modules/mongoose/lib/promise.js:70:20) 
    at /Users/admin/Node Projects/sandboxProject/node_modules/mongoose/lib/query.js:1087:15 

这似乎是它没有像“res.redirect(” /'+ member.username);“在“req.session.member_id = member._id;”之后。这是因为Mongoose findOne回调函数的异步性质吗?我尝试从回调中删除res.redirect,但会话数据不存储,当我把它留在那里,我得到“头已发送”错误。

我的配置:

app.configure(function(){ 
    app.set('views', __dirname + '/views'); 
    app.set('view engine', 'jade'); 
    app.use(express.cookieParser()); 
    app.use(express.session({ secret: "blahblah" })); 
    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(app.router); 
    app.use(express.static(__dirname + '/public')); 
}); 
+0

有固定的问题 - 原来,这是很简单,需要一点点常识! 由于来自Mongoose的回调是异步的,并在“res.redirect('/');”之后触发会话存储在我以前的路线的破碎版本。所有你需要做的就是处理回调中的失败,并放弃“res.redirect('/');”从路由回调结束。哎呀! –

+0

如果下面的解决方案有效,您能选择一个作为正确的答案,以帮助其他人解决同样的问题吗? – Brandon

回答

8

我也有类似的问题。尽管我的问题是,当我从会话中删除某些内容时,例如delete req.session.user,在重新加载和节点应用程序重新启动后,它仍会在那里。它只会在req.session.destroy()后消失。

我看着Node的会话middleware docs,发现他们有一个Session#save()方法。所以我在会话对象操作之后做了req.session.save(),它确实解决了我的问题。尝试一下,看看它是否修复了你的问题。

+0

虽然这个答案指出我在正确的方向,我会明确说明'req.session.save()'是一个以回调为参数的异步函数。所以任何依赖于保存数据的东西都应该在回调中执行。当使用内存存储进行开发时,这通常并不明显,并且“及时”发生。 –

4

问题是Member.findOne是异步的。当它的回调执行时,res.redirect('/')已经执行,它设置适当的HTTP响应头。您无法通过HTTP规则两次发送标头,因此错误Can't set headers after they are sent.

您可能希望将redirect('/')移动到您的密码匹配的else块中。