Рубрики
Без рубрики

Обращение с ошибками в Express

Как обрабатывать экспресс-ошибки

Автор оригинала: Zell Liew.

Мне было трудно изучить, как обращаться с ошибками в Express, когда я начал. Никто, казалось, не написал ответы, которые мне нужны, поэтому я должен был узнать это трудный путь.

Сегодня я хочу поделиться всем, что я знаю о обработке ошибок в приложении Express.

Давайте начнем с синхронных ошибок.

Обработка синхронных ошибок

Если вы хотите обрабатывать синхронную ошибку, вы можете бросить Ошибка в обработчике экспресс-запроса. (Примечание: обработчики запросов также называются контроллерами. Я предпочитаю говорить обработчики запроса, потому что они явные и легко понимать).

app.post('/testing', (req, res) => {
  throw new Error('Something broke! 😱')
})

Эти ошибки могут быть пойманы с экспресс-обработчиком ошибок. Если вы не написали пользовательский обработчик ошибок (подробнее об этом ниже), Express будет обрабатывать ошибку для вас обработчиком ошибок по умолчанию.

Обработчик ошибок Express по умолчанию будет:

  1. Установите статус HTTP на 500
  2. Отправляет текстовый ответ на запрос
  3. Журнал текстового ответа в консоли

Обработка асинхронных ошибок

Если вы хотите обрабатывать асинхронную ошибку, вам нужно отправить ошибку в оперативный обработчик Express через Следующий аргумент

app.post('/testing', async (req, res, next) => {
  return next(new Error('Something broke again! 😱'))
})

Если вы используете Async/ждут в приложении Express, вы хотите использовать функцию обертки, как Express-Async-Handler Отказ Это позволяет писать асинхронный код без пробных блоков. Я писал больше об этом в « », используя Async/ждут в Express “.

const asyncHandler = require('express-async-handler')

app.post('/testing', asyncHandler(async (req, res, next) => {
  // Do something
}))

Как только вы завернули обработчик запроса с Express-Async-Handler , ты можешь бросить Ошибка как раньше, и она будет обрабатываться с оперативным обработчиком ошибок.

app.post('/testing', asyncHandler(async (req, res, next) => {
  throw new Error('Something broke yet again! 😱')
}))

Написание пользовательского обработчика ошибок

Экспресс обработчики ошибок принимают четырех аргументов:

Они должны быть размещены после всех ваших подразгоний и маршрутов.

app.use(/*...*/)
app.get(/*...*/)
app.post(/*...*/)
app.put(/*...*/)
app.delete(/*...*/)

// Place your error handler after all other middlewares
app.use((error, req, res, next) => { /* ... */ })

Express перестанет использовать обработчик ошибок по умолчанию после создания пользовательского обработчика ошибок. Чтобы обработать ошибку, вам необходимо общаться с интерфейсом, который запрашивает конечную точку. Это означает, что вам нужно:

  1. Отправить на действительный код состояния HTTP
  2. Отправить действительный ответ

Допустимый код состояния HTTP зависит от того, что произошло. Вот список общих ошибок, которые вы должны подготовиться к:

  1. 400 неплохой ошибка запроса:
  • Используется, когда пользователь не содержит поле (например, информации о кредитной карте в форме оплаты)
  • Также используется, когда пользователь вводит некорректную информацию (пример: вводит различные пароли в полевом поле пароля и подтверждение пароля).
  1. 401 Несанкционированная ошибка: Используется, когда пользователь входит в неверную информацию для входа (например, имя пользователя, электронное письмо или пароль).
  2. 403 Запрещенная ошибка: Используется, когда пользователь не допускается доступа к конечной точке.
  3. 404 не найден ошибка: Используется, когда конечная точка не найдена.
  4. 500 Внутренняя ошибка сервера: Используется запрос, отправленный Frontend, является правильным, но произошла ошибка с бэкэнда.

Как только вы определили правильный код состояния HTTP, вы хотите установить статус с помощью res.status.

app.use((error, req, res, next) => {
  // Bad request error
  res.status(400)
  res.json(/* ... */)
})

Код состояния HTTP должен соответствовать сообщению об ошибке. Для кода состояния соответствует сообщению об ошибке, необходимо отправить код состояния вместе с ошибкой.

Самый простой способ – использовать http-errors упаковка. Это позволяет отправлять три вещи в свои ошибки:

  1. Код состояния
  2. Сообщение для перехода с ошибкой
  3. Любые свойства, которые вы хотели бы отправить. Это необязательно.

Установка http-errors :

npm install http-errors --save

Использование http-errors :

const createError = require('http-errors')

// Creating an error
throw createError(status, message, properties)

Давайте поработаем через пример вместе, чтобы сделать его более понятнее. Допустим, вы пытались найти пользователя по их адресу электронной почты. Пользователь не может быть найден. Вы хотите бросить ошибку, которая говорит «Пользователь не найден».

Когда вы создаете ошибку, вы хотите:

  1. Отправьте ошибку 400 плохой запроса (потому что пользователь заполнен неверной информацией). Вы отправляете это как первый параметр.
  2. Отправить сообщение, которое говорит «Пользователь не найден». Вы отправляете это как второй параметр.
app.put('/testing', asyncHandler(async (req, res) => {
  const { email } = req.body
  const user = await User.findOne({ email })

  // Throws error if user not found
  if (!user) throw createError(400, `User '${email}' not found`)
}))

Вы можете получить код статуса с Ошибка .status и сообщение об ошибке с Error.message Отказ

// Logging the error
app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})
Код статуса и сообщение об ошибке вошли в консоль.

Затем вы установили статус ошибки с помощью res.status Отказ Вы отправляете сообщение на res.json Отказ

app.use((error, req, res, next) => {
  // Sets HTTP status code
  res.status(error.status)

  // Sends response
  res.json({ message: error.message })
})

Лично я люблю отправлять статус, сообщение и трассировку стека для меня легко отладки.

app.use((error, req, res, next) => {
  // Sets HTTP status code
  res.status(error.status)

  // Sends response
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

Запасной код состояния

Если ошибка не возникла из CreateError он не будет иметь свойство статуса.

Вот пример. Допустим, вы пытались прочитать файл с Fs.readfile , но файл не существует.

const fs = require('fs')
const util = require('util')

// Converts readFile from callbacks to Async/await.
// Find out how to do this here: https://zellwk.com/blog/callbacks-to-promises
const readFilePromise = util.promisify(fs.readFile)

app.get('/testing', asyncHandler(async (req, res, next) => {
  const data = await readFilePromise('some-file')
})

Эта ошибка не будет содержать Статус имущество.

app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})
Ошибка не содержит свойство состояния

В этих случаях вы можете по умолчанию до 500 внутренней ошибки сервера.

app.use((error, req, res, next) => {
  res.status(error.status || 500)
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

Изменение состояния ошибки

Допустим, вы хотите получить файл с ввода пользователя. Если файл не существует, вы должны выбрасывать ошибку 400 плохого запроса, потому что это не ошибка вашего сервера.

В этом случае вы хотите использовать попробуйте/поймать Чтобы поймать оригинальную ошибку. Тогда вы воссоздаете ошибку с CreateError Отказ

app.get('/testing', asyncHandler(async (req, res, next) => {
  try {
    const { file } = req.body
    const contents = await readFilePromise(path.join(__dirname, file))
  } catch (error) {
    throw createError(400, `File ${file} does not exist`)
  }
})

Обработка 404 ошибок

Конечная точка не найдена, если запрос падает через все ваши подразнения и маршруты.

Чтобы обработать не обнаруженное ошибку, вы вставляете промежуточное программное обеспечение между маршрутами и обработчиком ошибок. Здесь создайте ошибку с CreateError Отказ

// Middlewares...
// Routes...

app.use((req, res, next) => {
  next(createError(404))
})

// Error handler...
Не найдено ошибка, отправленная клиенту.

Что касается «не может установить заголовки после их отправки клиенту»

Не паникуйте, если вы видите сообщение об ошибке «Невозможно установить заголовки после отправки на сервер».

Ошибка: не удается установить заголовки после отправки.

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

  1. res.send.
  2. res.json.
  3. res.render.runder.
  4. res.sendfile.
  5. Res.sendstatus.
  6. Отправить
  7. res.redirect.

Например, если вы запустите res.render и res.json В том же обработчике ответа вы получите «Невозможно установить заголовки после отправки» ошибки.

app.get('/testing', (req, res) => {
  res.render('new-page')
  res.json({ message: '¯\_(ツ)_/¯' })
})

Итак, если вы получите эту ошибку, дважды проверьте обработчики ответа, чтобы она не запускала вышеуказанные методы дважды.

При потоковой передаче

Если возникает ошибка, когда вы будете трансмировать ответ на интерфейс, вы получите то же самое «Невозможно установить заголовки» ошибки.

В этом случае экспресс-состояния вы должны делегировать обработку ошибок в обработчики Express по умолчанию. Он отправит ошибку и закрыть подключение для вас.

app.use((error, req, res, next) => {
  // Do this only if you're streaming a response
  if (res.headersSent) {
    return next(error)
  }

  // Rest of the error handlers
})

Это все, что я знаю сейчас!

Спасибо за прочтение. Эта статья была первоначально опубликована на мой блог Отказ Подпишись на Моя рассылка Если вы хотите больше статей, чтобы помочь вам стать лучшим разработчиком Frontend.