Разбор вопросов с собеседований по Express.js
Когда полезен Express.js?
Node.js особенно полезен при создании веб-приложений, где скорость и простота имеют первостепенное значение, а задача производить тяжеловесные вычисления не стоит. Вся прелесть в том, что Node.js использует неблокирующие ввод/вывод операции, Например, обработчик события, запускаемый в момент инициации события, может установить соединения с базой данных и назначить коллбек-функцию, которая должна выполниться, когда из БД будут получены данные. Node.js не ставит всё на паузу в ожидании результата от БД, а продолжает выполнять другие операции. Когда данные будут готовы, назначенный для их обработки коллбек будет выполнен. То, что Node.js не заблокировал все происходящие процессы ради ожидания выполнения функции, и является принципом неблокирующих операций. Сам Express.js лежит в основе многих других фреймворков для Node.js. Он славится своей стабильностью, большим сообществом и массой Open Source наработок. Однако, если вам действительно важна высокая производительность, не ошибкой было бы рассмотреть другие фреймворки.
Что такое middleware?
Middleware - это функция, выполняющаяся непосредственно перед тем, как выполнение перейдет к основному обработчику события. В Express.js это применяется для добавления специальной логики в цепочку обработки запроса. Middleware может модифицировать объекты запроса и ответа, выполнять асинхронные операции и передавать управление следующему Middleware или обработчику маршрута.
Что такое app.use()?
app.use()
- это функция, позволяющая вмонтировать middleware
в цепочку обработки запроса.
Вмонтированные middleware
вызываются в порядке их добавления, что позволяет выполнять операции последовательно.
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
Пример кода выше осуществляет логирование для каждого запроса к серверу, после чего с помощью next()
передает управление следующему middleware
или, если таковой отсутствует, непосредственно обработчику события.
Что такое next()?
Функция next()
используется в теле функции, вмонтированной в качестве middleware
, для того, чтобы передать управление следующему middleware
или, если таковой отсутствует, непосредственно обработчику события.
Как включить CORS?
Cross-Origin Resource Sharing (CORS) — это контролируемый и применяемый в принудительном порядке клиентом (браузером) механизм обеспечения безопасности на основе HTTP. Он позволяет службе (API) указывать любой источник (origin) помимо себя, с которого клиент может запрашивать ресурсы.
Если говорить проще, включение CORS на бэкенде позволит выполнять к нему HTTP-запросы не только с того же домена, к которому он привязан, но и с других. Каких именно - зависит от конкретной конфигурации, которую определяет сам разработчик.
Чтобы включить CORS в Express.js , необходимо использовать middleware
под названием cors
.
import cors from 'cors'
app.use(cors())
Это позволит выполнять запросы из любого источника. Для продвинутого контроля вы можете настроить CORS, передав объект options
основной функции.
Как следует обрабатывать ошибки?
Обработка ошибок в Express.js, как и многое другое, устроено через middleware
.
После всех маршрутов, для которых определяются обработчики, а также после всех иных middleware
, нужно зарегистрировать middleware
, который будет отвечать за обработку ошибок.
app.use(/*...*/)
app.get(/*...*/)
app.post(/*...*/)
app.put(/*...*/)
app.delete(/*...*/)
// middleware для обработки ошибок
app.use((error, req, res, next) => { /* ... */ })
Лучшие практики, которые можно привести по этой теме:
1. Централизация обработки ошибок: подразумевает создание централизованного обработчика, обрабатывающего все ошибки, которые могут возникнуть в приложении.
2. Использование HTTP статус-кодов: каждый ответ сервера должен иметь релевантный статус-код. Например, для ошибки сервера лучше отдавать статус 500, чтобы клиент мог среагировать на это соответствующим образом.
3. Логирование ошибок: все ошибки должны быть записаны в файл или отправлены специальный сервис, собирающий логи. Это позволит держать ситуацию под контролем и положительно повлияет на стабильность и надежность приложения.
4. Скрытие стек-трейсов: следует избегать прокидывания стек-трейсов клиентским приложениям - это риск для безопасности приложения.
5. Завершение работы и перезапуск: Если процесс сталкивается с необработанным исключением, необходимо обеспечить корректное завершение работы и перезапуск службы.
Как обеспечить безопасность в приложении?
Обеспечение безопасности в Express.js включает в себя несколько этапов.
Во-первых, используйте Helmet.js
для безопасной установки HTTP-заголовков и предотвращения распространенных веб-уязвимостей.
Во-вторых, реализуйте rate limiting с помощью таких модулей, как express-rate-limit
, для защиты от атак методом перебора.
В-третьих, проверяйте все входящие данные с помощью библиотеки, такой как express-validator
, чтобы избежать атак с использованием инъекций.
В-четвертых, используйте csurf
для защиты от CSRF.
В-пятых, обеспечьте безопасность файлов cookie
, установив флаг "secure"
и атрибуты ‘HttpOnly’
.
В-шестых, конфигурируйте middleware CORS для ограничения запросов с доменов, не относящихся к приложению.
Наконец, обновляйте зависимости, чтобы снизить риски, связанные с известными уязвимостями в сторонних пакетах.
Как реализовать rate limiting?
Один из вариантов - это использование express-rate-limit
.
let limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 100 // не более 100 запросов в windowMs на каждый IP
});
app.use("/api/", limiter);
Такое решение ограничивает количество запросов от конкретного пользователя (по IP) в интервале 15 минут до 100. В случае превышения будет отдан HTTP-статус 429 (Too Many Requests)
.
Как реализовать аутентификацию?
Аутентификация в Express.js может быть реализована с помощью middleware Passport.js
.
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
app.use(passport.authenticate())
Все, что осталось:
app.use(passport.authenticate())
Какие есть способы отладки приложения?
Одним из распространенных методов отладки в Express.js является использование встроенного отладчика в Node.js , который позволяет пошагово просматривать код и проверять переменные.
Другим популярным инструментом является модуль debug
, который предоставляет простой доступ к отладочной информации. Он гибкий и поддерживает пространства имен для разных частей приложения.
Middleware, такие как Morgan
или Winston
, также используются для регистрации HTTP-запросов и ошибок соответственно. Они предоставляют подробные журналы о входящих запросах и ответах сервера, помогая выявлять проблемы.
Для более продвинутой отладки можно использовать такие инструменты, как node-inspector
или встроенный отладчик Visual Studio Code. Они предлагают графический интерфейс для установки точек останова, пошагового выполнения кода и проверки переменных.
Как обеспечить версионирование API?
Версионирование API может быть реализовано в Express.js несколькими методами.
Популярный подход - это URL-версионирование, когда разные версии API расположены по соответствующим им адресам (например, ‘/v1/users’
, ‘/v2/users’
). Этот метод прост и легок в реализации.
Другая стратегия заключается в использовании специальных заголовков запроса. В этом случае клиент определяет необходимую версию API установкой специального заголовка, например ‘Accept-version: v1’.
Третий вариант известен как content negotiation (согласование контента). Он заключается в том, что клиент указывает необходимую версию в заголовке 'Accept'
. Например, ‘Accept: application/vnd.myapi.v1+json’
.
В чём разница между res.send() и res.json()?
res.send()
используется для отправки ответа с любым типом данных (строка, объект, буфер и т.д.).
res.json()
используется для отправки ответа в формате JSON (автоматически устанавливает заголовок Content-Type: application/json
).
Также в этой категории
Вам может быть интересно
Топ тредов
: Задача в JS под названием "Соревнование" содержит ошибку
![Логотип Девстанции Логотип Девстанции](/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flogo.767d6ec0.png&w=48&q=75)
: Добавьте возможность ставить реакции на решенные задачи других коллег)
: Добавьте разделы по MongoDB и Nest.js
![Логотип Девстанции Логотип Девстанции](/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flogo.767d6ec0.png&w=48&q=75)