express.js асинхронный маршрутизатор и обработка ошибок - PullRequest
2 голосов
/ 28 апреля 2019

У меня есть асинхронная функция в качестве обработчика маршрута, и я хотел бы, чтобы ошибки обрабатывались как некое промежуточное ПО. Вот моя попытка работы:

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 промежуточных упаковщика, в идеале я бы хотел использовать только функцию бизнес-логики и как-то объявить, что каждый маршрут обернут в эти. Даже объединение двух промежуточных программ было бы неплохо, но мне не удалось.

Ответы [ 4 ]

1 голос
/ 28 апреля 2019

Я использую следующий подход:

Создание 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 голос
/ 28 апреля 2019

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);
}
0 голосов
/ 29 апреля 2019

То, что я в итоге сделал, это объединение оболочек следующим образом:

const routeProvider = routeHandlerFn => async (req, res, next) => {
  try {
    const {status = 200, body = {}} = await routeHandlerFn(req.query)
    res.status(status).json(body)
  } catch(error) {
    next(error)
  }
}

Эта оболочка - все, что нужно для любого маршрута.Он ловит неожиданные ошибки и предоставляет обработчику маршрута необходимые параметры.

0 голосов
/ 28 апреля 2019

Что вы можете сделать, это добавить обработчики ошибок после ваших маршрутов. 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!')
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...