express.js异步路由器和错误处理

时间:2019-04-28 07:13:43

标签: javascript node.js express

我有一个异步功能作为路由处理程序,并且我想将错误作为某种中间件来处理。这是我的工作尝试:

router.get(
  "/",
  asyncMiddleware(
    routeProviderMiddleware(
      async ({ y }) => ({
        body: await db.query({x: y})
      })
    )
  )
)

// This is the middleware that catches any errors from the business logic and calls next to render the error page
const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next)
  }

// This is a middleware that provides the route handler with the query and maybe some other services that I don't want the route handler to explicitly access to
const routeProviderMiddleware = routeHandlerFn => async (req, res) => {
  const {status = 200, body = {}} = await routeHandlerFn(req.query)
  res.status(status).json(body)
}

我努力做到的是使路由声明更整洁的一种方法-我不希望在那里有2个中间件包装器,理想情况下,我只希望在那里使用业务逻辑功能,并以某种方式声明将每个路由都包裹在其中这些。 甚至将两个中间件组合在一起也很好,但是我却没管。

5 个答案:

答案 0 :(得分:1)

我使用以下方法:

创建asyncWrap作为辅助中间件:

const asyncWrap = fn =>
  function asyncUtilWrap (req, res, next, ...args) {
    const fnReturn = fn(req, res, next, ...args)
    return Promise.resolve(fnReturn).catch(next)
  }

module.exports = asyncWrap

您的所有路由/中间件/控制器都应使用此asyncWrap处理错误:

router.get('/', asyncWrap(async (req, res, next) => {
  let result = await db.query({x: y})
  res.send(result)
}));

app.js,最后一个中间件将收到所有asyncWrap的错误:

// 500 Internal Errors
app.use((err, req, res, next) => {
  res.status(err.status || 500)
  res.send({
    message: err.message,
    errors: err.errors,
  })
})

答案 1 :(得分:1)

Express允许使用路由的中间件列表,这种方法对我而言有时比高阶函数更好(它们有时看起来像过度设计)。

示例:

app.get('/',
  validate,
  process,
  serveJson)

function validate(req, res, next) {
  const query = req.query;
  if (isEmpty(query)) {
    return res.status(400).end();
  }
  res.locals.y = query;
  next();
}

function process(req, res, next) {
  Promise.resolve()
  .then(async () => {
    res.locals.data = await db.query({x: res.locals.y});
    next();
  })
  .catch((err) =>
    res.status(503).end()
  );
}

function serveJson(req, res, next) {
  res.status(200).json(res.locals.data);
}

答案 2 :(得分:1)

Express 5 自动正确处理异步错误

https://expressjs.com/en/guide/error-handling.html 目前明确表示:

<块引用>

从 Express 5 开始,返回 Promise 的路由处理程序和中间件将在拒绝或抛出错误时自动调用 next(value)。例如:

app.get('/user/:id', async function (req, res, next) {
 var user = await getUserById(req.params.id)
 res.send(user)
})

如果 getUserById 抛出错误或拒绝,next 将使用抛出的错误或拒绝的值调用。如果没有提供拒绝值,next 将使用 Express 路由器提供的默认 Error 对象调用。

我在实验中证明了这一点:Passing in Async functions to Node.js Express.js router

这意味着您将能够直接调用 async 并从中使用 await,而无需任何额外的包装器:

router.get("/", async (req, res) => 
  const obj = await db.query({x: req.params.id})
  // Use obj normally.
)

错误将被自动正确处理。

答案 3 :(得分:0)

您可以做的是在路由后添加错误处理程序。 https://expressjs.com/en/guide/error-handling.html

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

答案 4 :(得分:0)

我最终要做的是像这样统一包装器:

<ion-item class="my-item5" > 
    <ion-icon name='podium' item-right color="gray"></ion-icon>
    <ion-label class="gen-col">Select age</ion-label>
    <ion-select value="age" okText="Ok" cancelText="Cancel">                                       
        <ion-select-option value="18">18</ion-select-option>
        <ion-select-option value="19">19</ion-select-option>
        <ion-select-option value="20">20</ion-select-option>
        <ion-select-option value="21">21</ion-select-option>
    </ion-select>
</ion-item>

此包装器是所有路由所需要的。它捕获了意外错误,并为路由处理程序提供了所需的参数。