Сжатие — gzip и brotli

gzip и brotli — алгоритмы сжатия текстовых HTTP-ресурсов (HTML, CSS, JS, JSON), которые уменьшают их объём в 2-5 раз при передаче по сети. Brotli даёт на 15-25% лучшее сжатие по сравнению с gzip.

Зачем нужно

Сжатие — самая простая оптимизация с максимальным эффектом: 100KB JavaScript → 30KB с gzip → 26KB с brotli. Для медленных соединений (3G, мобайл) разница в несколько мегабайт — разница между пользователем, который дождался страницы, и тем, кто ушёл.

Где используется

  • Все текстовые ресурсы: HTML, CSS, JS, JSON, XML, SVG, font woff
  • REST API и GraphQL-ответы
  • Server-Sent Events и WebSocket фреймы (частично)

Основной контент

Сравнение алгоритмов

gzip:   Поддерживается везде, быстрое сжатие/распаковка
brotli: Лучшее сжатие (+15-25% vs gzip), браузеры с 2015, Nginx с 1.11.5

Поддержка браузерами (2026): brotli — 96%+
Правило: используй brotli с gzip fallback

Nginx: gzip + brotli

# nginx.conf
http {
  # gzip (fallback для старых клиентов)
  gzip on;
  gzip_comp_level 5;
  gzip_min_length 256;
  gzip_proxied any;
  gzip_vary on;
  gzip_types
    text/plain text/css application/json
    application/javascript text/xml application/xml
    application/xml+rss text/javascript image/svg+xml;

  # brotli (требует модуль ngx_brotli)
  brotli on;
  brotli_comp_level 6;
  brotli_min_length 256;
  brotli_types
    text/plain text/css application/json
    application/javascript text/xml application/xml
    image/svg+xml;
}

Express + Compression middleware

const express = require('express');
const compression = require('compression');
const shrinkRay = require('shrink-ray-current'); // gzip + brotli

const app = express;

// Опция 1: только gzip (простое решение)
app.use(compression({
  level: 6,       // Уровень сжатия 1-9 (6 - баланс скорость/размер)
  threshold: 1024, // Не сжимать ответы < 1KB
}));

// Опция 2: brotli + gzip (лучше)
app.use(shrinkRay);

Статическое сжатие (pre-compression)

# Сжать файлы при сборке, отдавать готовые .gz и .br
# Vite/webpack делают это через плагины

# vite.config.js
import viteCompression from 'vite-plugin-compression';

export default {
  plugins: [
    viteCompression({ algorithm: 'gzip' }),
    viteCompression({ algorithm: 'brotliCompress', ext: '.br' }),
  ],
};
# Nginx: отдавать pre-compressed файлы
location ~* \.(js|css|html|svg)$ {
  gzip_static on;    # Ищет file.js.gz
  brotli_static on;  # Ищет file.js.br
}

Проверка сжатия

# Проверить наличие Content-Encoding в ответе
curl -I -H "Accept-Encoding: br, gzip" https://example.com/bundle.js \
  | grep -i 'content-encoding\|content-length'

# Ожидаемый ответ:
# content-encoding: br
# content-length: 26458  # Сжатый размер

# Без сжатия:
# content-length: 98000  # ~4x больше

Что НЕ сжимать

# Уже сжатые форматы — не трогать!
# JPEG, PNG, WEBP, AVIF, GIF  → уже сжаты
# WOFF2  → уже сжат (brotli внутри формата)
# MP4, MP3, ZIP, PDF          → уже сжаты

# Сжатие этих форматов только добавляет CPU overhead без выгоды

Частые ошибки

  • Не включён gzip_vary on в Nginx — CDN кеширует один вариант для всех
  • Сжатие очень маленьких ответов (<256 bytes) — overhead заголовков превышает выгоду
  • Не добавлен Accept-Encoding в Vary — браузер/CDN не различает сжатый и несжатый
  • Высокий уровень сжатия (9) в real-time — CPU bottleneck при высоком трафике

Связанные темы

Ресурсы