Фреймворк Express для серверной разработки на Node.js

Раздел: Веб-разработка -> Веб-фреймворк Express

Основы работы с Express.js

Как установить Express.js и создать первое приложение?

Основной способ установки и запуска Express.js включает инициализацию проекта npm, установку пакета express и создание файла сервера. Выполняются команды:

npm init -y\nnpm install express

Express js (express.js)

Создается файл server.js с минимальным кодом:

const express = require('express');\nconst app = express();\nconst port = 3000;\napp.get('/', (req, res) => {\n  res.send('Hello World!');\n});\napp.listen(port, () => {\n  console.log(`Сервер запущен на порту ${port}`);\n});

Запуск приложения осуществляется командой node server.js. После этого в браузере по адресу http://localhost:3000 отображается сообщение "Hello World!".

Альтернативный подход использует генератор приложений express-generator. Установка:

npx express-generator myapp\ncd myapp\nnpm install\nnpm start

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

Типичные проблемы: порт 3000 может быть занят другим процессом. В таком случае происходит ошибка EADDRINUSE. Решение: изменить номер порта в коде или завершить процесс, использующий порт. Еще одна ошибка – отсутствие модуля express после установки. Необходимо убедиться, что команда npm install express выполнена в корневой папке проекта, где находится package.json.

Как настроить маршруты с параметрами и обрабатывать разные HTTP методы?

Основная маршрутизация в Express строится на методах объекта app, соответствующих HTTP-глаголам: get, post, put, delete. Параметры пути задаются через двоеточие, а доступ к ним осуществляется через req.params. Пример:

app.get('/users/:userId', (req, res) => {\n  const userId = req.params.userId;\n  res.send(`Пользователь ${userId}`);\n});\napp.post('/users', (req, res) => {\n  const body = req.body;\n  res.send('Пользователь создан');\n});

Для получения данных из строки запроса используется req.query. Например: /search?q=express.

Для улучшения организации кода применяется express.Router. Маршруты выносятся в отдельные файлы:

// users.js\nconst router = express.Router();\nrouter.get('/', (req, res) => res.send('Список пользователей'));\nmodule.exports = router;\n\n// server.js\nconst usersRouter = require('./users');\napp.use('/users', usersRouter);

Такой подход упрощает поддержку и тестирование.

Ошибка: порядок middleware имеет значение. Если маршрут с параметром (например, /users/:id) определен после общего маршрута /users, то общий маршрут перехватит запросы. Решение: располагать более специфичные маршруты перед общими. Также часто забывают добавить парсер тела запроса для POST: необходимо подключить express.json() или express.urlencoded().

Как добавить промежуточные обработчики (middleware) для логирования и проверки доступа?

Собственный middleware создается как функция с тремя параметрами (req, res, next) и вызывается через app.use(). Пример логгера:

const logger = (req, res, next) => {\n  console.log(`${req.method} ${req.url}`);\n  next();\n};\napp.use(logger);

Middleware для проверки аутентификации может прервать цепочку, отправив статус 401:

const auth = (req, res, next) => {\n  const token = req.headers['authorization'];\n  if (token === 'secret') {\n    next();\n  } else {\n    res.status(401).send('Неавторизованный доступ');\n  }\n};\napp.use('/protected', auth);

Популярные сторонние middleware: morgan для логирования, helmet для безопасности, cors для кросс-доменных запросов. Установка и подключение:

npm install morgan helmet cors\nconst morgan = require('morgan');\nconst helmet = require('helmet');\nconst cors = require('cors');\napp.use(morgan('combined'));\napp.use(helmet());\napp.use(cors());

Частая ошибка: middleware не вызывает next(), из-за чего запрос зависает. Необходимо всегда завершать обработку либо вызовом next, либо отправкой ответа. Еще проблема – неправильный порядок: middleware для авторизации должно быть подключено до маршрутов, которые оно защищает.

Как обслуживать статические файлы и шаблоны?

Для статических файлов (CSS, изображения) используется встроенный middleware express.static. Папка с файлами указывается в параметрах:

app.use(express.static('public'));

Файлы из папки public становятся доступны по корневому URL. Для шаблонизации подключается движок, например EJS. Установка и настройка:

npm install ejs\napp.set('view engine', 'ejs');\napp.set('views', './views');

Пример шаблона index.ejs:

<h1><%= title %></h1><p>Добро пожаловать</p>

Вызов в маршруте:

app.get('/page', (req, res) => {\n  res.render('index', { title: 'Главная' });\n});

Другие популярные шаблонизаторы: Pug (ранее Jade) и Handlebars. Пример для Pug:

npm install pug\napp.set('view engine', 'pug');\n// Файл index.pug:\n// h1= title\n// p Добро пожаловать

Для Handlebars используется пакет express-handlebars.

Типичные проблемы: неправильный путь к папке с шаблонами – движок не находит файлы. Необходимо убедиться, что директория views существует и содержит файлы с соответствующим расширением. Также ошибка возникает, если не установлен сам пакет шаблонизатора или не указан view engine.

Расширенные примеры использования Express.js

Асинхронные функции в middleware и обработка ошибок

При работе с асинхронными операциями, такими как запросы к базе данных, необходимо корректно передавать ошибки в Express. Для этого используется обертка, которая возвращает middleware, вызывающий next при возникновении ошибки.

Пример

const asyncHandler = fn => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

app.get('/data', asyncHandler(async (req, res) => {
  const result = await fetchSomeData();
  res.json(result);
}));

// Если fetchSomeData выбрасывает исключение, оно будет перехвачено и передано в next.
// Результат: при ошибке запроса возвращается статус 500 с сообщением ошибки (если определен middleware для обработки ошибок).
// Пример ответа при успехе: { "data": [...] }
// Пример ответа при ошибке: Статус 500, тело "Internal Server Error" (зависит от реализации error middleware)

Загрузка файлов с multer

Multer – middleware для обработки multipart/form-data. Позволяет сохранять загруженные файлы на диск или в память.

Пример

const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) => {
  const file = req.file;
  if (!file) {
    return res.status(400).send('Файл не загружен');
  }
  res.send(`Файл ${file.originalname} загружен, размер ${file.size} байт`);
});

// Для загрузки нескольких файлов используется upload.array('files', maxCount)
// При отправке POST запроса с файлом в поле "file" сервер возвращает сообщение о загрузке.
// Файл сохраняется в папку uploads с сгенерированным именем.
// Пример ответа: "Файл photo.jpg загружен, размер 12345 байт"

Вложенные роутеры и middleware на уровне роутера

Создание иерархии маршрутов с использованием options `mergeParams` для доступа к параметрам родительского роутера.

Пример

const parentRouter = express.Router();
const childRouter = express.Router({ mergeParams: true });

// Middleware, применяемый только к дочернему роутеру
childRouter.use((req, res, next) => {
  console.log(`Дочерний роутер, userId: ${req.params.userId}`);
  next();
});

childRouter.get('/', (req, res) => {
  res.send(`Список постов пользователя ${req.params.userId}`);
});

childRouter.get('/:postId', (req, res) => {
  res.send(`Пост ${req.params.postId} пользователя ${req.params.userId}`);
});

parentRouter.use('/users/:userId/posts', childRouter);

app.use('/api', parentRouter);
// GET /api/users/123/posts -> Список постов пользователя 123
// GET /api/users/123/posts/456 -> Пост 456 пользователя 123
// В консоли выводится: "Дочерний роутер, userId: 123"

Express.js - comments

En
Express js (javascript)