处理服务/控制器层中 Express.js 中的错误

nap*_*993 4 javascript node.js express

我正在 Express.js 中编写一个具有单独的控制器层和服务层的应用程序。这是我当前的代码:

用户服务.js

exports.registerUser = async function (email, password) {
  const hash = await bcrypt.hash(password, 10);
  const countUser = await User.countDocuments({email: email});
  if(countUser > 0) {
    throw ({ status: 409, code: 'USER_ALREADY_EXISTS', message: 'This e-mail address is already taken.' });
  }
  const user = new User({
    email: email,
    password: hash
  });
  return await user.save();
};

exports.loginUser = async function (email, password) {
  const user = await User.findOne({ email: email });
  const countUser = await User.countDocuments({email: email});
  if(countUser === 0) {
    throw ({ status: 404, code: 'USER_NOT_EXISTS', message: 'E-mail address does not exist.' });
  }
  const validPassword = await bcrypt.compare(password, user.password);
  if (validPassword) {
    const token = jwt.sign({ email: user.email, userId: user._id }, process.env.JWT_KEY, { expiresIn: "10s" });
    return {
      token: token,
      expiresIn: 3600,
      userId: user._id
    }
  } else {
    throw ({ status: 401, code: 'LOGIN_INVALID', message: 'Invalid authentication credentials.' });
  }
};
Run Code Online (Sandbox Code Playgroud)

用户控制器.js

exports.userRegister = async function (req, res, next) {
  try {
    const user = await UserService.registerUser(req.body.email, req.body.password);
    res.status(201).json({ data: user });
  } catch (e) {
    if(!e.status) {
      res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
    } else {
      res.status(e.status).json( { error: { code: e.code, message: e.message } });
    }
  }
}

exports.userLogin = async function (req, res, next) {
  try {
    const user = await UserService.loginUser(req.body.email, req.body.password);
    res.status(200).json({ data: user });
  } catch (e) {
    if(!e.status) {
      res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
    } else {
      res.status(e.status).json( { error: { code: e.code, message: e.message } });
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

该代码可以工作,但需要一些更正。我在错误处理方面遇到问题。我只想处理一些错误。如果发生其他错误,将返回 500 内部服务器错误。

1)我可以使用服务层的“抛出”对象吗?这是一个好的做法吗?

2)如何避免每个控制器中重复此代码:

if(!e.status) {
    res.status(500).json( { error: { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred.' } });
} else {
    res.status(e.status).json( { error: { code: e.code, message: e.message } });
}
Run Code Online (Sandbox Code Playgroud)

3)代码是否需要其他更正?我刚刚学习 Node.js,我想写好应用程序的其余部分。

l2y*_*sho 7

  1. 是的,您可以从服务层抛出错误,最好在控制器中使用 try/catch 块捕获错误

  2. 我使用自定义错误中间件处理此问题,只需在 catch 块中使用 next 函数即可。

    catch (e) {
        next(e)
    }
    
    Run Code Online (Sandbox Code Playgroud)

    错误中间件示例(有关更多信息,请检查文档,填写免费信息以将中间件移动到文件)

      app.use(function (err, req, res, next) {
          // err is error from next(e) function
          // you can do all error processing here, logging, parsing error messages, etc...
          res.status(500).send('Something broke!')
      })
    
    Run Code Online (Sandbox Code Playgroud)
  3. 从我的角度来看,它看起来不错。如果您正在寻找一些最佳实践和工具,请尝试使用eslint(例如使用 AirBnb 配置)进行 linting,尝试使用 dotenv进行环境变量管理,另请参阅Node.js 最佳实践