【问题标题】:Handle exceptions on every Express route处理每条 Express 路线上的异常情况
【发布时间】:2021-04-20 02:20:40
【问题描述】:

我希望对每条路由进行一些基本的错误处理,因此如果出现异常,API 至少会响应 500。

根据this pattern,你仍然需要在每条路由中包含一个try/catch 块:

app.post('/post', async (req, res, next) => {
  const { title, author } = req.body;
  
  try {
    if (!title || !author) {
      throw new BadRequest('Missing required fields: title or author');
    }
    const post = await db.post.insert({ title, author });
    res.json(post);
  } catch (err) {
    next(err) // passed to the error-handling middleware
  }
});

这似乎有点重复。是否有更高级别的方法可以在任何地方自动捕获异常并将其传递给中间件?

我的意思是,我显然可以定义自己的appGet()

function appGet(route, cb) {
    app.get(route, async (req, res, next) => {
        try {
          await cb(req, res, next);
        } catch (e) {
            next(e);
        }
    });
}

有这个的内置版本吗?

【问题讨论】:

    标签: node.js express error-handling middleware


    【解决方案1】:

    您可以使用express-promise-router 包。

    Express 4 路由器的简单包装器,允许中间件返回承诺。这个包通过减少重复代码,使得在处理 Promise 时为 Express 编写路由处理程序变得更加简单。

    例如

    app.ts:

    import express from 'express';
    import Router from 'express-promise-router';
    import bodyParser from 'body-parser';
    const router = Router();
    const app = express();
    const port = 3000;
    app.use(bodyParser.json());
    app.use(router);
    
    router.post('/post', async (req, res) => {
      const { title, author } = req.body;
      if (!title || !author) {
        throw new Error('Missing required fields: title or author');
      }
      const post = { title, author };
      res.json(post);
    });
    
    router.use((err, req, res, next) => {
      res.status(500).send(err.message);
    });
    
    app.listen(port, () => console.log(`Server started at http://localhost:${port}`));
    

    你不再需要try/catch 语句块了。

    测试结果:

    【讨论】:

      【解决方案2】:

      我认为更好的方法是划分服务和控制器,如下所示。

      添加邮政服务:

      async function addPostService (title, author) => {
          if (!title || !author)
            throw new BadRequest('Missing required fields: title or author');
          
          return await db.post.insert({ title, author });
      };
      

      添加后期控制器:

      function addPost(req, res, next){
          const { title, author }= req.body;
      
          addPostService
            .then((post) => {
              res.json(post);
            })
            .catch(next) // will go through global error handler middleware
      }
      

      现在,我们可以创建一个全局错误处理程序中间件,该中间件将捕获整个应用程序中任何控制器抛出的错误。

      function globalErrorHandler(err, req, res, next){
        switch(true){
          case typeof err === 'string':
            // works for any errors thrown directly
            // eg: throw 'Some error occured!';
            return res.status(404).json({ message: 'Error: Not found!'});
          
          // our custom error
          case err.name = 'BadRequest':
            return res.status(400).json({ message: 'Missing required fields: title or author!'})
          
          default:
            return res.status(500).json({ message: err.message });
        }
      }
      

      而且,不要忘记在启动服务器之前使用错误处理程序中间件。

      // ....
      app.use(globalErrorHandler);
      app.listen(port, () => { console.log('Server started...')});
      

      【讨论】:

      • 嗯,有用的想法,谢谢。它仍然在每条路由中都包含一个异常处理程序(这里稍微伪装成.catch(...)
      • 其实想想也没有别的办法。根据业务需求,显然每条路由都涉及错误处理。处理错误有两种选择:一种是 try-catch 和 async-await,或者返回 promise 并使用 .catch()。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2020-05-13
      • 2019-08-16
      • 1970-01-01
      • 2013-12-23
      相关资源
      最近更新 更多