Compression для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Compression для JavaScript (Node.js): полное руководство с примерами

1. Что это и зачем нужна

Библиотека compression для Node.js — это middleware (промежуточное ПО) для фреймворка Express (и других совместимых фреймворков), которое автоматически сжимает HTTP-ответы сервера с помощью алгоритмов Gzip, Deflate или Brotli. Она является стандартом де-факто для оптимизации производительности веб-приложений на Node.js, так как позволяет значительно уменьшить размер передаваемых данных (HTML, CSS, JavaScript, JSON, изображения и т.д.) между сервером и клиентом.

Зачем это нужно? В современном вебе скорость загрузки страниц критически важна для пользовательского опыта и SEO. Сжатие данных позволяет уменьшить объем трафика в 3–10 раз (в зависимости от типа контента). Например, HTML-файл размером 100 КБ после Gzip-сжатия может весить всего 10–15 КБ. Это особенно актуально для мобильных пользователей с ограниченным трафиком и для API, возвращающих большие JSON-объекты. Без использования compression сервер будет отдавать "сырые" данные, что увеличивает время загрузки и нагрузку на сеть.

Библиотека полностью автоматизирует процесс: она проверяет заголовок Accept-Encoding в запросе клиента, выбирает подходящий алгоритм сжатия (обычно gzip или brotli, если поддерживается), сжимает ответ и добавляет соответствующие заголовки (Content-Encoding, Vary). Разработчику нужно лишь подключить middleware в цепочку обработки запросов Express. Это делает compression незаменимым инструментом для любого production-приложения на Node.js.

2. Установка

Библиотека устанавливается через npm (Node Package Manager). Убедитесь, что у вас установлен Node.js (версия 12 или выше). Выполните команду в корне вашего проекта:

npm install compression

Если вы используете yarn:

yarn add compression

После установки библиотека будет доступна для импорта в вашем коде.

3. Быстрый старт — минимальный рабочий пример

Самый простой способ начать использовать compression — подключить его как middleware в Express. Ниже приведен минимальный сервер, который сжимает все ответы:

const express = require('express');
const compression = require('compression');
const app = express();
const port = 3000;

// Подключаем middleware сжатия
app.use(compression());

// Обычный маршрут
app.get('/', (req, res) => {
  // Отправляем большой ответ (повторяем строку 1000 раз)
  const bigData = 'Hello, World! '.repeat(1000);
  res.send(bigData);
});

app.listen(port, () => {
  console.log(`Сервер запущен на http://localhost:${port}`);
});

После запуска (node app.js) откройте браузер на http://localhost:3000. В инструментах разработчика (вкладка Network) вы увидите, что ответ сжат (заголовок Content-Encoding: gzip). Размер ответа будет в разы меньше исходного.

4. Основные методы/функции/классы

Библиотека compression предоставляет одну основную функцию — middleware, которая настраивается через объект опций. Рассмотрим 8 ключевых аспектов работы с ней.

4.1. compression([options]) — создание middleware

Сигнатура: compression(options?: CompressionOptions): RequestHandler

Что делает: Создает и возвращает функцию middleware для Express. Принимает необязательный объект с настройками.

Пример:

const compression = require('compression');
const app = require('express')();

// Без опций (стандартное поведение)
app.use(compression());

// С опциями
app.use(compression({
  level: 6,          // Уровень сжатия (0-9)
  threshold: 1024,   // Не сжимать ответы меньше 1 КБ
  filter: (req, res) => {
    // Собственная логика фильтрации
    return !req.headers['x-no-compression'];
  }
}));

4.2. Опция level — уровень сжатия

Сигнатура: level: number (от 0 до 9)

Что делает: Определяет степень сжатия. 0 — без сжатия (только упаковка), 1 — быстрое, но слабое сжатие, 9 — максимальное сжатие (медленнее). По умолчанию: -1 (означает стандартный уровень zlib, обычно 6).

Пример:

app.use(compression({ level: 9 })); // Максимальное сжатие, но больше нагрузка на CPU

4.3. Опция threshold — порог сжатия

Сигнатура: threshold: number | string (в байтах)

Что делает: Устанавливает минимальный размер ответа (в байтах), при котором применяется сжатие. Ответы меньше этого порога не сжимаются. По умолчанию: 1024 (1 КБ). Можно указать строку, например '1kb'.

Пример:

app.use(compression({ threshold: 0 })); // Сжимать все ответы, даже маленькие
app.use(compression({ threshold: '5kb' })); // Сжимать только ответы больше 5 КБ

4.4. Опция filter — фильтр для выборочного сжатия

Сигнатура: filter: (req: Request, res: Response) => boolean

Что делает: Позволяет задать функцию, которая решает, нужно ли сжимать конкретный ответ. Функция получает объекты запроса и ответа. Должна вернуть true (сжимать) или false (не сжимать). По умолчанию используется встроенная функция, которая проверяет Content-Type и не сжимает уже сжатые форматы (изображения, видео).

Пример:

app.use(compression({
  filter: (req, res) => {
    // Не сжимаем ответы для определенных путей
    if (req.path.startsWith('/api/stream')) return false;
    // Используем стандартную логику для остальных
    return compression.filter(req, res);
  }
}));

4.5. Опция chunkSize — размер чанка

Сигнатура: chunkSize: number (в байтах)

Что делает: Определяет размер внутреннего буфера (чанка) для сжатия. По умолчанию: 16384 (16 КБ). Влияет на использование памяти и скорость. Увеличение может улучшить сжатие, но требует больше памяти.

Пример:

app.use(compression({ chunkSize: 32 * 1024 })); // 32 КБ

4.6. Опция memLevel — уровень использования памяти

Сигнатура: memLevel: number (от 1 до 9)

Что делает: Определяет, сколько памяти выделяется для внутренних структур сжатия. 1 — минимум памяти (медленнее), 9 — максимум памяти (быстрее). По умолчанию: 8.

Пример:

app.use(compression({ memLevel: 9 })); // Максимальная скорость, больше памяти

4.7. Опция strategy — стратегия сжатия

Сигнатура: strategy: number (константы zlib)

Что делает: Определяет алгоритм сжатия. Возможные значения: zlib.constants.Z_DEFAULT_STRATEGY (0), Z_FILTERED (1), Z_HUFFMAN_ONLY (2), Z_RLE (3), Z_FIXED (4). По умолчанию: Z_DEFAULT_STRATEGY. Для данных, которые уже частично сжаты (например, PNG), может быть полезна стратегия Z_FILTERED.

Пример:

const zlib = require('zlib');
app.use(compression({
  strategy: zlib.constants.Z_FILTERED
}));

4.8. Опция windowBits — размер окна сжатия

Сигнатура: windowBits: number

Что делает: Определяет размер окна (истории) для алгоритма Deflate. Значение от 8 до 15. По умолчанию: 15 (максимальное окно, лучшее сжатие). Меньшие значения уменьшают использование памяти, но снижают степень сжатия.

Пример:

app.use(compression({ windowBits: 12 })); // Меньше памяти, хуже сжатие

5. Реальный практический пример (100-200 строк кода)

Ниже представлен полноценный сервер на Express с использованием compression, который включает логирование, обработку ошибок, статические файлы и API. Пример демонстрирует типичную production-конфигурацию.

const express = require('express');
const compression = require('compression');
const path = require('path');
const fs = require('fs');
const app = express();
const PORT = process.env.PORT || 3000;

// 1. Настройка compression с кастомными опциями
app.use(compression({
  level: 6,                    // Хороший баланс скорость/сжатие
  threshold: 256,              // Сжимаем ответы от 256 байт
  filter: (req, res) => {
    // Не сжимаем уже сжатые форматы и Server-Sent Events
    if (req.headers['accept'] === 'text/event-stream') return false;
    // Используем стандартный фильтр для остального
    return compression.filter(req, res);
  }
}));

// 2. Middleware для логирования запросов
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const duration = Date.now() - start;
    const size = res.get('Content-Length') || 'chunked';
    const encoding = res.get('Content-Encoding') || 'none';
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url} - ${res.statusCode} (${size} bytes, encoding: ${encoding}, ${duration}ms)`);
  });
  next();
});

// 3. Раздача статических файлов (сжатие будет применено автоматически)
app.use(express.static(path.join(__dirname, 'public'), {
  maxAge: '1d',                // Кеширование на 1 день
  etag: true,
  lastModified: true
}));

// 4. API эндпоинт: возвращает большой JSON
app.get('/api/data', (req, res) => {
  // Генерируем массив из 1000 объектов
  const largeData = Array.from({ length: 1000 }, (_, i) => ({
    id: i,
    name: `User ${i}`,
    email: `user${i}@example.com`,
    description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(10)
  }));
  res.json(largeData);
});

// 5. API эндпоинт: возвращает HTML-страницу
app.get('/report', (req, res) => {
  const html = `

Отчет

  

Большой отчет

${'Текст отчета. '.repeat(500)}

`; res.type('html').send(html); }); // 6. Эндпоинт для скачивания файла (сжатие будет применено) app.get('/download', (req, res) => { const filePath = path.join(__dirname, 'data.txt'); // Создаем большой файл, если его нет if (!fs.existsSync(filePath)) { fs.writeFileSync(filePath, 'A'.repeat(1024 * 100)); // 100 КБ } res.download(filePath); }); // 7. Обработка ошибок app.use((err, req, res, next) => { console.error('Ошибка:', err); res.status(500).json({ error: 'Внутренняя ошибка сервера' }); }); // 8. Запуск сервера app.listen(PORT, () => { console.log(`Сервер запущен на http://localhost:${PORT}`); console.log('Тестовые эндпоинты:'); console.log(' GET /api/data - большой JSON'); console.log(' GET /report - большая HTML страница'); console.log(' GET /download - скачивание файла'); });

Этот пример показывает, как compression интегрируется в реальное приложение: он автоматически сжимает JSON, HTML, статические файлы и даже файлы для скачивания. Логирование помогает отследить, какие ответы были сжаты и насколько эффективно.

6. Советы по производительности и типичные ошибки

Советы по производительности

  • Не используйте максимальный уровень сжатия (9) для динамических ответов. Уровень 6 (по умолчанию) дает отличный баланс между степенью сжатия и временем обработки. Уровень 9 может увеличить загрузку CPU на 50-100% при незначительном выигрыше в размере (1-3%).
  • Настройте порог (threshold) разумно. Сжатие маленьких ответов (менее 1 КБ) неэффективно — накладные расходы на заголовки и алгоритм могут превысить выгоду. Оставьте значение по умолчанию 1024 байта или уве

Рекомендаций