node.js - 在 express 发送错误时防止代码重复的最有效方法

标签 node.js express promise

我正在使用我的 Express 应用程序编写登录函数,但不喜欢回调链中大量重复的 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 返回的 bool 值。 我不是一个后端工程师,这只是一个个人项目,但我想知道 Node.js 世界中的最佳实践是什么。

当我们这样做时,我不确定在这些错误情况下发送的适当状态代码是什么,因为我确信 500 不正确。

最佳答案

我会像这样重写你的代码,其中我们只有一个.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
    });

}

While we're at it, I'm not sure what the appropriate status code to send in these error cases would be, as I am sure 500 is not correct.

你是对的,为每个错误设置 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?

关于node.js - 在 express 发送错误时防止代码重复的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49744549/

相关文章:

javascript - Meteor.wrapAsync

node.js - 始终将变量传递给 Express res.render

node.js - ExpressJS 与 MeteorJS

javascript - node.js 本地模块 : module not found error in subfolder

node.js - createReadStream 的 TypeScript 定义不接受选项中的 {start : 90, end: 99 }

javascript - LESS — data-uri 画家 mixin

javascript - promise 和并发

javascript - 如何使用返回 Promises 的 NAPI 创建异步函数

javascript - 如何在 Node JS 中使用 jwt 向所有用户授权不同的 token

c++11 - 将 std::promise 对象存储在 std::pair 中