Skip to main content
Практика завдань

Як реалізувати кешування в Express.js для покращення продуктивності?

Кешування в Express.js

Кешування зберігає часто запитувані дані в швидкому доступному шарі, щоб зменшити час відповіді та навантаження на сервер. Це одна з найефективніших оптимізацій продуктивності.


Типи кешування

1. Кешування в пам'яті (node-cache)

Найкраще підходить для розгортань на одному сервері:

js
const NodeCache = require('node-cache'); const cache = new NodeCache({ stdTTL: 300, checkperiod: 60 }); function cacheMiddleware(duration) { return (req, res, next) => { const key = req.originalUrl; const cached = cache.get(key); if (cached) { return res.json(cached); } const originalJson = res.json.bind(res); res.json = (body) => { cache.set(key, body, duration); originalJson(body); }; next(); }; } // Кеш на 5 хвилин app.get('/api/products', cacheMiddleware(300), async (req, res) => { const products = await db.query('SELECT * FROM products'); res.json(products); });

2. Кешування в Redis (Розподілене)

Найкраще підходить для розгортань на кількох серверах:

js
const Redis = require('ioredis'); const redis = new Redis(process.env.REDIS_URL); function redisCacheMiddleware(ttl = 300) { return async (req, res, next) => { const key = `cache:${req.originalUrl}`; try { const cached = await redis.get(key); if (cached) { return res.json(JSON.parse(cached)); } } catch (err) { console.error('Помилка Redis:', err); } const originalJson = res.json.bind(res); res.json = async (body) => { try { await redis.setex(key, ttl, JSON.stringify(body)); } catch (err) { console.error('Помилка запису в Redis:', err); } originalJson(body); }; next(); }; } app.get('/api/products', redisCacheMiddleware(600), getProducts);

3. HTTP заголовки кешування

Дозволяють браузерам і CDN кешувати відповіді:

js
// Cache-Control для публічного кешованого контенту app.get('/api/products', (req, res) => { res.set('Cache-Control', 'public, max-age=300'); // 5 хв res.json(products); }); // Без кешу для приватних даних app.get('/api/profile', auth, (req, res) => { res.set('Cache-Control', 'private, no-cache'); res.json(user); }); // Кешування на основі ETag const etag = require('etag'); app.get('/api/data', (req, res) => { const data = getData(); const tag = etag(JSON.stringify(data)); if (req.headers['if-none-match'] === tag) { return res.status(304).end(); // Не змінено } res.set('ETag', tag); res.json(data); });

4. Інвалідація кешу

js
// Інвалідувати при операціях запису app.post('/api/products', async (req, res) => { const product = await createProduct(req.body); // Інвалідувати пов'язані кеші cache.del('/api/products'); await redis.del('cache:/api/products'); res.status(201).json(product); }); // Інвалідація на основі шаблону з Redis async function invalidatePattern(pattern) { const keys = await redis.keys(pattern); if (keys.length > 0) { await redis.del(...keys); } } // Інвалідувати всі кеші продуктів await invalidatePattern('cache:/api/products*');

Порівняння стратегій кешування

СтратегіяШвидкістьМасштабованістьПостійністьСценарій використання
В пам'ятіНайшвидшаОдин серверНіМаленькі додатки, розробка
RedisДуже швидкаБагато серверівТакПродукційні API
HTTP заголовкиКлієнтськаПідходить для CDNБраузерСтатичний контент
CDNНайшвидша для користувачівГлобальнаНа краюАктиви, публічні API

Що кешувати

КешуватиНе кешувати
Результати запитів до бази данихДані, специфічні для користувача (якщо не Redis)
Відповіді зовнішніх APIДані в реальному часі (ціни акцій)
Обчислені/агреговані даніТокени аутентифікації
Статичний контентТочки з важкими записами

Золоте правило: Кешуйте агресивно, інвалідуйте обережно. Починайте з коротких TTL (30-60с) і збільшуйте на основі частоти змін даних. Завжди майте спосіб примусово інвалідувати при зміні даних.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань