Введение
Исключения и ошибки неизбежны, когда пользователи взаимодействуют с любым приложением, и инженеры-программисты должны выбрать средства для обработки любой ошибки, которая может возникнуть — сознательно или неосознанно. В результате бэкэнд-разработчики, создающие API с помощью Express, вынуждены работать над тем, чтобы создать полезный, эффективный и удобный API. Что наиболее важно, так это обрабатывать ошибки таким образом, чтобы построить надежную систему, потому что это помогает сократить время разработки, прямые ошибки, проблемы с производительностью и определяет успех или масштабируемость разработки программного обеспечения.
Вам нужно зарегистрировать сообщение об ошибке, подавить ошибку, уведомить пользователей об ошибке или написать код для обработки ошибок? Не удивляйтесь больше.
В этом руководстве мы узнаем, как создать надежную кодовую базу обработки ошибок для приложений Express, которая поможет обнаруживать ошибки приложений и предпринимать оптимальные действия для восстановления любого приложения после корректного сбоя во время выполнения.
Примечание: Мы будем использовать Postman для тестирования API в нашей демонстрации. Вы можете скачать его на Страница загрузки почтальона. Кроме того, вы можете просто использовать браузер, командную строку curl
инструмент или любой другой инструмент, с которым вы, возможно, знакомы.
Что такое обработка ошибок?
В разработке программного обеспечения есть два разных типа исключений: оперативный и программный.
- Операционные сбои могут возникать во время выполнения, и чтобы предотвратить внезапное завершение работы приложения, мы должны изящно обрабатывать эти исключения с помощью эффективных методов обработки ошибок.
- Программные исключения создаются вручную программистом при возникновении исключительного состояния.
Вы можете думать об операционных исключениях как о «неожиданных, но предвиденных» исключениях (таких как доступ к индексу за пределами границ), а о программных исключениях как о «ожидаемых и предвидимых» исключениях (таких как исключение форматирования чисел).
Обработка исключений — это процедура, используемая для поиска и исправления ошибок в программе. Обработка ошибок отправляет сообщения, содержащие тип произошедшей ошибки и стек, в котором произошла ошибка.
Примечание: В компьютерных науках исключения могут быть устранены и обычно связаны с операционными или программными проблемами во время выполнения. Ошибки обычно возникают из-за внешних факторов, таких как аппаратные ограничения, проблемы с подключением, нехватка памяти и т. д. В JavaScript эти термины часто используются взаимозаменяемо, а пользовательские исключения получаются из Error
класс. В Error
сам класс представляет как ошибки, так и исключения.
В Express обработка исключений относится к тому, как Express настраивается для перехвата и обработки синхронных и асинхронных исключений. Преимущество обработки исключений в Express заключается в том, что вам как разработчику не нужно писать собственные обработчики исключений; Express поставляется с обработчиком исключений по умолчанию. Обработчик исключений помогает выявлять ошибки и сообщать о них пользователю. Он также предоставляет различные стратегии исправления и реализует их для смягчения исключений.
Хотя может показаться, что под капотом скрывается множество вещей, обработка исключений в Express не замедляет общий процесс программы и не приостанавливает ее выполнение.
Понимание обработки исключений в Express
С обработчиком ошибок по умолчанию, который поставляется с Express, у нас есть набор функций промежуточного программного обеспечения, которые помогают автоматически обнаруживать ошибки в обработчиках маршрутов. Вскоре мы создадим проект, чтобы применить теорию на практике о том, как возвращать правильные ошибки в приложении Express и как не допустить утечки конфиденциальной информации.
Определение функции промежуточного программного обеспечения в Express
Функции промежуточного программного обеспечения для обработки ошибок определены таким образом, что они принимают Error
object в качестве первого входного параметра, за которым следуют параметры по умолчанию любой другой функции промежуточного программного обеспечения: request
, response
качества next
, next()
функция пропускает все текущее промежуточное ПО к следующему обработчику ошибок для маршрутизатора.
Настройка обработки ошибок в Express
Выполните следующую команду в своем терминале, чтобы создать приложение Node и Express:
$ mkdir error-handling-express
Во вновь созданной папке инициализируем новый проект Node:
$ cd error-handling-express && npm init -y
Это создает package.json
файл в нашей папке.
Чтобы создать сервер Express в нашем приложении Node, нам нужно установить express
пакет, dotenv
для автоматической загрузки переменных окружения в .env
файл в process.env
объект и nodemon
для перезапуска приложения узла, если в каталоге отмечено изменение файла.
$ npm install express dotenv nodemon
Затем создайте app.js
файл в папке проекта, который будет служить индексным файлом для приложения.
Теперь, когда мы установили все необходимые зависимости для нашего приложения Express, нам нужно настроить скрипт для чтения приложения в package.json
файл. Чтобы добиться этого, package.json
файл, так что scripts
объект, как показано ниже:
"scripts": {
"start": "nodemon app.js"
},
Кроме того, вы можете пропустить использование nodemon
и использовать node app.js
.
Настройка экспресс-сервера
Чтобы настроить сервер, мы должны сначала импортировать различные пакеты в app.js
. Мы также создадим .env
файл в каталоге проекта — для хранения всех переменных окружения для приложения:
const express = require('express')
require('dotenv').config
PORT=4000
Мы определили номер порта для приложения в .env
, который загружается и читается dotenv
, и к ним можно будет получить доступ позже.
Инициализация экспресс-сервера
Теперь нам нужно инициализировать сервер Express и заставить наше приложение прослушивать номер порта приложения вместе с запросом на тестовый маршрут — /test
. Обновим app.js
, под операторами импорта:
const app = express();
const port = process.env.PORT || 4000;
app.get("/test", async (req, res) => {
return res.status(200).json({ success: true });
});
app.listen(port, () => {
console.log(`Server is running at port ${port}`);
});
С этого момента мы узнаем, как обрабатывать различные варианты использования операционных ошибок, которые могут возникнуть в Express.
Обработка ошибок Not Found в Express
Предположим, вам нужно получить всех пользователей из базы данных пользователей, вы можете эффективно справиться с потенциальным сценарием ошибки, когда в базе данных нет данных, обернув логику в try/catch
блокировать — в надежде поймать любую ошибку, которая может возникнуть в catch
Блок:
const getUser = () => undefined;
app.get("/get-user", async (req, res) => {
try {
const user = getUser();
if (!user) {
throw new Error('User not found');
}
} catch (error) {
console.log(error);
res.status(400).send(error.message)
}
return res.status(200).json({
success: true
});
});
Это приводит к:
User not found
Теперь, когда этот запрос сделан (вы можете проверить с помощью Postman), а в базе данных нет пользователя, клиент получает сообщение об ошибке «Пользователь не найден». Кроме того, вы заметите, что ошибка также регистрируется в консоли.
Оптимизация обработки ошибок с помощью ПО промежуточного слоя обработчика ошибок
Мы можем оптимизировать разработку, создав промежуточное программное обеспечение для обработки ошибок, которое будет находиться в конце всех определенных маршрутов, так что, если на одном из маршрутов возникает ошибка, Express автоматически просматривает следующее промежуточное программное обеспечение и продолжает двигаться вниз по списку. пока не достигнет обработчика ошибок. Обработчик ошибок обработает ошибку, а также отправит ответ клиенту.
Ознакомьтесь с нашим практическим руководством по изучению Git с рекомендациями, принятыми в отрасли стандартами и прилагаемой памяткой. Перестаньте гуглить команды Git и на самом деле изучить это!
Для начала создайте папку с именем middleware
в каталоге проекта и в этой папке создайте файл с именем errorHandler.js
который определяет обработчик ошибок:
const errorHandler = (error, req, res, next) => {
console.log(error);
res.status(400).send(error.message);
}
module.exports = errorHandler;
В нашей промежуточной функции мы дали Express понять, что это не базовая промежуточная функция, а обработчик ошибок, добавив error
перед тремя основными параметрами.
Теперь мы будем использовать обработчик ошибок в нашей демонстрации. app.js
и обработайте первоначальную ошибку выборки пользователей с помощью промежуточного программного обеспечения обработчика ошибок, как показано ниже:
const getUser = () => undefined;
app.get("/get-user", async (req, res, next) => {
try {
const user = getUser();
if (!user) {
throw new Error("User not found");
}
} catch (error) {
return next(error);
}
});
app.use(errorHandler);
Мы можем еще больше оптимизировать наш код, создав абстракцию вокруг try/catch
логика. Мы можем добиться этого, создав новую папку в каталоге проекта с именем utils
, и в нем создайте файл с именем tryCatch.js
.
Чтобы абстрагироваться от try-catch
логика — мы можем определить функцию, которая принимает другую функцию (известную как контроллер) в качестве параметра и возвращает async
функция, которая будет содержать try/catch
для любого полученного контроллера.
Если в контроллере возникает ошибка, она фиксируется в catch
блок и вызывается следующая функция:
const tryCatch = (controller) => async (req, res, next) => {
try {
await controller(req, res);
} catch (error) {
return next(error);
}
};
module.exports = tryCatch;
Для try/catch
абстракция, мы можем реорганизовать наш код, чтобы сделать его более кратким, пропуская try-catch
предложение явно при выборке пользователей в app.js
:
const getUser = () => undefined;
app.get(
"/get-user",
tryCatch(async (req, res) => {
const user = getUser();
if (!user) {
throw new Error("User not found");
}
res.status(400).send(error.message);
})
);
Мы успешно абстрагировались от логики try-catch, и наш код по-прежнему работает так же, как и раньше.
Обработка ошибок проверки в Express
Для этой демонстрации мы создадим новый маршрут в нашем приложении Express для входа в систему — для проверки идентификатора пользователя при входе в систему. Сначала мы установим joi
package, чтобы помочь с созданием схемы, с помощью которой мы можем обеспечить соблюдение требований:
$ npm i joi
Далее создайте схему, которая Joi.object
с userId
который должен быть числом и является обязательным — это означает, что запрос должен соответствовать объекту с идентификатором пользователя.
Мы можем использовать validate()
метод в объекте схемы для проверки каждого ввода по схеме:
const schema = Joi.object({
userId: Joi.number().required(),
});
app.post(
"/login",
tryCatch(async (req, res) => {
const {error, value} = schema.validate({});
if (error) throw error;
})
);
Если пустой объект передается в validate()
метод, ошибка будет изящно обработана, и сообщение об ошибке будет отправлено клиенту:
На консоли мы также получаем доступ к details
массив, который включает в себя различные сведения об ошибке, которые могут быть сообщены пользователю в случае необходимости.
Чтобы специально обрабатывать ошибки проверки таким образом, чтобы передавать соответствующие сведения об ошибке для каждой ошибки проверки, промежуточное программное обеспечение обработчика ошибок может быть реорганизовано:
const errorHandler = (error, req, res, next) => {
console.log(error);
if (error.name === "ValidationError") {
return res.status(400).send({
type: "ValidationError",
details: error.details,
});
}
res.status(400).send(error.message);
};
module.exports = errorHandler;
Доступно errorHandler.js
теперь настроено, когда мы делаем тот же запрос с пустым объектом, переданным в validate()
Метод:
Теперь у нас есть доступ к настроенному объекту, который возвращает сообщения в более читаемом/дружественном виде. Таким образом, мы можем отправлять и обрабатывать различные типы ошибок в зависимости от типа поступающей ошибки.
Заключение
В этом руководстве мы рассмотрели все аспекты обработки ошибок в Express.js, в том числе то, как синхронный и асинхронный код обрабатывается по умолчанию, как создавать собственные классы ошибок, как писать собственные функции промежуточного программного обеспечения для обработки ошибок и предоставлять next
как последний обработчик catch
Как и в случае с любой другой задачей, во время разработки также используются передовые методы, в том числе эффективная обработка ошибок, и сегодня мы узнали, как мы можем надежно обрабатывать ошибки в приложении Express.
Правильная обработка ошибок означает не только сокращение времени разработки за счет легкого поиска багов и ошибок, но и разработку надежной кодовой базы для крупномасштабных приложений. В этом руководстве мы увидели, как настроить промежуточное ПО для обработки операционных ошибок. Некоторые другие способы улучшить обработку ошибок включают в себя: отказ от отправки трассировки стека, изящную остановку процессов для обработки неперехваченных исключений, предоставление соответствующих сообщений об ошибках, отправку журналов ошибок и настройку класса, который расширяет Error
класса.
Я надеюсь, что примеры, которые я использовал в этом уроке, были вам интересны. Я рассмотрел различные сценарии управления ошибками, с которыми вы потенциально можете столкнуться при написании приложения Express для использования в реальном мире. Пожалуйста, дайте мне знать, если я что-то пропустил. Это принесет пользу нам и поможет мне узнать больше. Хорошего дня и спасибо за чтение.
Вы можете обратиться ко всему исходному коду, использованному в статье, на Github.