在express中发送错误时防止代码重复的最有效方法

时间:2018-04-10 02:53:41

标签: node.js express promise

我正在使用我的快递应用程序编写登录功能,并且不喜欢在回调链中有很多res.status(500).send(body)重复的事实:

router.post('/login', (req, res) => {

  User.findOne({ 
    where: { username: req.body.username } 
  })
    .then( user => {
      if (user) {
        User.verifyPassword(req.body.password, user)
          .then((verified) => {
            if (verified) {
              let signedToken = jwt.sign(
                { user: user.id },
                'secret',
                { expiresIn: 24 * 60 * 60 }
              );

              res.status(200).send({
                token: signedToken,
                userId:  user.id,
                username: user.username 
              });
            } else {
              // If password entered does not match user password 
              res.status(500).send({ error: true, });
            }
          })
          // If bycrpt explodes
          .catch((error) => {
            res.status(500).send({ error: error, });
          });
      } else {
        // If we can't even find a user with that username
        res.status(500).send({ error: true, });
      }
    })
    // If the db query to find a user explodes
    .catch(error => {
      res.status(500).send({ error: error });
    });
});

其中两个与模糊的异常相关,这些异常会导致API爆炸。另外两个基于API返回的布尔值。 我不是一个后端工程师,这只是一个个人项目,但我想知道Node.js世界中最好的做法是什么。

虽然我们正在使用它,但我不确定在这些错误情况下发送的相应状态代码是什么,因为我确信500是不正确的。

1 个答案:

答案 0 :(得分:0)

我会像这样重写你的代码,我们只有一个.catch

router.post('/login', (req, res) => {

    User.findOne({  where: { username: req.body.username }})
        .then(user => {

            if (!user) // If we can't even find a user with that username
                return Promise.reject(true); // You should probably return an Error

            return User.verifyPassword(req.body.password, user)

        })
        .then((verified) => {

            if (!verified) // If password entered does not match user password 
                return Promise.reject(true); // You should probably return an Error

            let signedToken = jwt.sign({
                    user: user.id
                },
                'secret', {
                    expiresIn: 24 * 60 * 60
                }
            );

            res.status(200).send({
                token: signedToken,
                userId: user.id,
                username: user.username
            });

        }).catch(error => {

            // If the db query to find a user explodes
            // If we can't even find a user with that username
            // If password entered does not match user password             

            // You could throw different errors and handle
            // all of them differently here
            res.status(500).send({
                error: error
            });
        });
});

使用async/await

可以进一步改善这一点
router.post('/login', async(req, res) => {

    try {

        const user = await User.findOne({   where: { username: req.body.username }});

        if (!user) // If we can't even find a user with that username
            throw new Error('Invalid username');

        const verified = await User.verifyPassword(req.body.password, user)

        if (!verified) // If password entered does not match user password 
            throw new Error('Invalid password');

        let signedToken = jwt.sign({
                user: user.id
            },
            'secret', {
                expiresIn: 24 * 60 * 60
            }
        );

        res.status(200).send({
            token: signedToken,
            userId: user.id,
            username: user.username
        });

    } catch(error) {

        // If the db query to find a user explodes
        // If we can't even find a user with that username
        // If password entered does not match user password             
        res.status(500).send({
            error: error.message
        });

    }

});

关于状态代码,有多种方法可以处理它们,我通常会为每个状态代码抛出一个特定的错误。

<强> errors.js

class Unauthorized extends Error {

    constructor(message) {
        super(message);     
        this.name = 'UnauthorizedError';
        this.statusCode = 401
    }
}

class BadRequest extends Error {

    constructor(message) {
        super(message);     
        this.name = 'BadRequestError';
        this.statusCode = 400
    }
}

/** more errors... **/

module.exports = {
    Unauthorized,
    BadRequest
};

所以我们现在可以设置正确的状态代码:

const { Unauthorized } = require('./errors');
/* ... */

try {

    /* ... */
    if (!verified) // Some people may say 422 status code... 
        throw new Unauthorized('Invalid password');

    /* ... */
} catch(error) {

    res.status(error.statusCode || 500).send({
        error: error.message
    });

}
  

虽然我们正在使用它,但我不确定适当的状态代码是什么   发送这些错误的情况将是,因为我确定500是不正确的。

你是对的,为每个错误设置500是不正确的。我会给你留下一些可能有助于你设置正确状态代码的问题,因为在这个问题上讨论它会太长。

What's an appropriate HTTP status code to return by a REST API service for a validation failure?

What's the appropriate HTTP status code to return if a user tries logging in with an incorrect username / password, but correct format?