Bookshelf / Passport:发送后不能设置标题

时间:2017-06-20 06:53:07

标签: node.js express passport.js bookshelf.js

我在路由器的控制台中遇到了一些错误。快递路线如下:

router.get('/getInfo/:id', function(req, res, next) {
  return passport.authenticate('jwt', {session: false}, function(err, account, info) {
   if (err) { return next(err);}
   if (!account) { 
    new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
    }); 
   }
   if(account._id != req.params.id) { 
    new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
    });
   }
   else { 
    new Account({_id: req.params.id}).fetch().then(function(acc){ 
        return res.status(200).send(acc.toJSON());
    });
   }
  })(req, res, next);
});

错误消息仅在我未经过身份验证时显示 - 它显示

Unhandled rejection Error: Can't set headers after they are sent.
...
at null.<anonymous> (/-----/routes/users.js:61:27)

第61行是带有(account._id!= req.params.id)的块中的res.status(200)..

代码背后的想法是,如果您要求的用户信息不是您(由jwt验证),您只能获得一些信息 - 现在只有&#39; first_name&#39;。如果您要求提供有关您自己的信息,您会看到所有信息。

最让我烦恼的是每次打电话给路线时我都会得到有效的回复。服务器没有崩溃/拒绝加载/ .. - 我得到了我期望的结果。

1 个答案:

答案 0 :(得分:0)

我认为这来自对承诺的不当使用

问题在于你写这个

if (!account) { 
    new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
    }); 
   }

你实际上并没有从你的函数返回而是创建一个新帐户并获得res.status(200)...的承诺执行,但是你继续到下一行if ... else ...,在那里你也可以得到一个承诺另一个res.status(200)...

所以你确实试图将标题设置两次,因此错误。

要解决此问题,您需要多种解决方案

(1)在ifs

中为所有行添加'return`
router.get('/getInfo/:id', function(req, res, next) {
  return passport.authenticate('jwt', {session: false}, function(err, account, info) {
    if (err) { return next(err);}
    if (!account) { 
      return new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      }); 
    }
    if(account._id != req.params.id) { 
      return new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      });
    }
    else { 
      return new Account({_id: req.params.id}).fetch().then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      });
    }
  })(req, res, next);
});

(2)将ifs链接起来,确保每次调用只执行一次

router.get('/getInfo/:id', function(req, res, next) {
  return passport.authenticate('jwt', {session: false}, function(err, account, info) {
    if (err) { return next(err);}
    if (!account) { 
      new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      }); 
    } else if(account._id != req.params.id) { 
      new Account({_id: req.params.id}).fetch({columns: ['first_name']}).then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      });
    } else { 
      new Account({_id: req.params.id}).fetch().then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      });
    }
  })(req, res, next);
});

(3)或者你稍微重构你的代码,使其更符合promises的意图。实际上,您有3种不同的方式来创建帐户,但只有一种方法可以结束通话。我会更明确地说明。这会产生类似

的东西
router.get('/getInfo/:id', function(req, res, next) {
  return passport.authenticate('jwt', {session: false}, function(err, account, info) {
    if (err) { return next(err);}
    let createAccountPromise;
    if (!account) { 
      createAccountPromise = new Account({_id: req.params.id}).fetch({columns: ['first_name']});
    } else if(account._id != req.params.id) { 
      createAccountPromise = new Account({_id: req.params.id}).fetch({columns: ['first_name']});
    } else { 
      createAccountPromise = new Account({_id: req.params.id}).fetch();
    }

    return createAccountPromise
      .then(function(acc){ 
        return res.status(200).send(acc.toJSON());
      }); 
  })(req, res, next);
});