Какой подход обработки запросов использует Express.js?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Подход обработки запросов в Express.js
Express.js использует middleware pipeline подход (также известный как chain of responsibility pattern) для обработки HTTP запросов. Это последовательное прохождение запроса через цепочку обработчиков.
Основной принцип
Каждый middleware — это функция, которая имеет доступ к объектам request (req), response (res) и next middleware'у:
const express = require('express');
const app = express();
// Middleware 1
app.use((req, res, next) => {
console.log('1. Middleware 1');
next(); // Передача управления следующему middleware
});
// Middleware 2
app.use((req, res, next) => {
console.log('2. Middleware 2');
next();
});
// Обработчик маршрута (тоже middleware)
app.get('/users', (req, res) => {
console.log('3. Route handler');
res.json({ users: [] });
});
// Порядок выполнения: 1 -> 2 -> 3 обработчик маршрута
Типы middleware в Express
Application-level middleware — применяется ко всем или определённым маршрутам:
// Глобальный middleware (для всех запросов)
app.use(express.json());
// Selective middleware (только для /api маршрутов)
app.use('/api', (req, res, next) => {
console.log('API request');
next();
});
Router-level middleware — применяется к определённому роутеру:
const router = express.Router();
router.use((req, res, next) => {
console.log('User router middleware');
next();
});
router.get('/', (req, res) => {
res.json({ users: [] });
});
app.use('/users', router);
Built-in middleware — встроенные в Express:
app.use(express.json()); // Парсинг JSON
app.use(express.urlencoded()); // Парсинг form data
app.use(express.static('public')); // Статические файлы
Third-party middleware — внешние пакеты:
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
app.use(helmet()); // Безопасность
app.use(cors()); // CORS
app.use(morgan('combined')); // Логирование
Custom middleware — собственные функции:
// Аутентификация
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'No token' });
}
// Проверка токена
req.user = { id: 1, name: 'John' };
next();
};
app.use(authMiddleware);
// Логирование
const logMiddleware = (req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next();
};
app.use(logMiddleware);
Error-handling middleware — обработка ошибок (4 параметра!):
// Должны иметь ровно 4 параметра для работы как error handler
app.use((err, req, res, next) => {
console.error('Error:', err.message);
res.status(500).json({ error: err.message });
});
// Это НЕ будет error handler (только 3 параметра)
app.use((req, res, next) => {
// ...
});
Полный цикл обработки запроса
const express = require('express');
const app = express();
// Шаг 1: Парсинг тела запроса
app.use(express.json());
// Шаг 2: Логирование
app.use((req, res, next) => {
console.log('LOG:', `${req.method} ${req.url}`);
next();
});
// Шаг 3: Аутентификация
app.use((req, res, next) => {
const token = req.headers.authorization;
if (token) {
req.user = { id: 1 }; // Упрощённо
}
next();
});
// Шаг 4: Маршруты
app.get('/users', (req, res) => {
console.log('Getting users for user:', req.user?.id);
res.json({ users: [{ id: 1, name: 'John' }] });
});
app.post('/users', (req, res) => {
console.log('Creating user:', req.body);
res.status(201).json({ id: 2, ...req.body });
});
// Шаг 5: 404 обработчик
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});
// Шаг 6: Error handling
app.use((err, req, res, next) => {
console.error('ERROR:', err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(3000);
// Порядок выполнения для GET /users:
// 1. express.json() middleware
// 2. Логирование middleware
// 3. Аутентификация middleware
// 4. Обработчик GET /users
// 5. Ответ отправлен
Управление потоком
next() — передаёт управление следующему middleware:
app.use((req, res, next) => {
console.log('1');
next(); // -> переход к следующему
});
app.use((req, res, next) => {
console.log('2');
// Если не вызвать next(), цепь разрывается
});
app.use((req, res, next) => {
console.log('3'); // Не выполнится, если выше не вызван next()
});
Краткие ответы — остановка цепи:
app.use((req, res, next) => {
if (req.path === '/admin' && !req.user?.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
// return остановит выполнение
}
next();
});
Обработка ошибок — skip middleware и перейти к error handler:
app.use((req, res, next) => {
try {
// Some code
} catch (err) {
next(err); // Передаёт в error middleware
}
});
// Error middleware поймёт ошибку
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message });
});
Преимущества подхода
Модульность — разделение логики на независимые middleware.
Переиспользуемость — один middleware применить к нескольким маршрутам.
Гибкость — легко добавлять, удалять, переупорядочивать обработчики.
Читаемость — цепь middleware читается как последовательность шагов.
Важные замечания
Express использует синхронный подход в цепи middleware. Если middleware содержит асинхронный код, нужно правильно обработать Promises:
// ✓ Правильно
app.use(async (req, res, next) => {
try {
const data = await fetchData();
req.data = data;
next();
} catch (err) {
next(err);
}
});
// ✗ Неправильно (async ошибка не будет поймана)
app.use((req, res, next) => {
fetchData().then(() => next());
// Если ошибка в .then() — ничего не поймает
});
Middleware pipeline в Express — это мощный и гибкий подход, который позволяет строить сложные приложения из простых, модульных компонентов.