使用Router()参数进行快递

Express using the Router() params

本文关键字:快递 参数 Router 使用      更新时间:2023-09-26

假设我使用express的Router()获得了这段代码。

authRoute.param('token', function(req, res, next, token) {
    User.findOne({ 'local.resetPasswordToken': req.params.token, resetPasswordExpires: { $gt: Date.now() }}, function(err, user) {
        if (!user) {
            req.flash('error', 'error msg here');
            return res.redirect('/forgot');
        }
        req.user = user;
    })
    next();
})
authRoute.route('/reset/:token')
    .get(function(req, res) {
        res.render('reset', {
            user: req.user
        })
    })

我得到这个错误:

_http_outgoing.js:346
    throw new Error('Can''t set headers after they are sent.');
    ^
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)

如果没有Router(),它看起来就是这样:

app.get('/reset/:token', function(req, res) {
  User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
    if (!user) {
      req.flash('error', 'Password reset token is invalid or has expired.');
      return res.redirect('/forgot');
    }
    res.render('reset', {
      user: req.user
    });
  });
});

Router.param端出了什么问题?我阅读了给出的错误消息,了解到当试图在已经设置的响应上设置标头时会发生这种情况。

您正在authRout.param中立即调用next(),从而允许其他中间件在调用Mongoose回调之前,在某个时刻调用res.end()(res.render、res.send等)。我的假设是,当允许中间件执行(前面解释过),然后在其中一个中间件已经"结束"响应后调用res.redirect('/forgot')时,会出现此错误。

解决方案是在继续中间件链之前等待数据库响应,这只是一个异步问题。考虑以下内容:

authRoute.param('token', function(req, res, next, token) {
    User.findOne({ 'local.resetPasswordToken': req.params.token, resetPasswordExpires: { $gt: Date.now() }}, function(err, user) {
        // pass error to middlewares
        if (err) return next(err)
        // Stop the middleware chain i.e. return res.redirect
        if (!user) {
            req.flash('error', 'error msg here');
            return res.redirect('/forgot');
        }
        req.user = user;
        // important! call `next()` after mongo response
        next()
    })
})

在单个请求处理程序(后一个示例)中不会发生这种情况,因为您正确地处理了async,而不是在调用Mongoose回调之前结束http响应。