Перейти к содержимому
27 / 36

Как работает сжатие ответов (gzip, Brotli)?


Полный ответ

Процесс согласования сжатия:

JavaScript
Браузер                                    Сервер
|  |
| -- GET /app.js |
| Accept-Encoding: gzip, deflate, br  --> |
|  |
| [Сервер выбирает лучший алгоритм] |
|  |
| <-- 200 OK |
| Content-Encoding: br |
| Content-Type: application/javascript |
| [сжатое тело ответа] |
|  |
| [Браузер распаковывает автоматически] |

Настройка на nginx:

Nginx

# nginx.conf

# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;           # 1-9, баланс скорости и степени сжатия
gzip_min_length 256;         # не сжимать мелкие ответы
gzip_types
  text/plain
  text/css
  text/javascript
  application/javascript
  application/json
  application/xml
  image/svg+xml
  font/woff2;

# Brotli (нужен модуль ngx_brotli)
brotli on;
brotli_comp_level 6;         # 1-11, для on-the-fly обычно 4-6
brotli_types
  text/plain
  text/css
  text/javascript
  application/javascript
  application/json
  application/xml
  image/svg+xml;

Предварительное сжатие (статические файлы):

Bash

# Сжатие при сборке -- максимальный уровень, не тратит CPU на лету

# gzip
gzip -k -9 dist/app.js        # создаёт app.js.gz рядом с оригиналом

# Brotli (уровень 11 -- максимальный, медленный, но лучшее сжатие)
brotli -k -q 11 dist/app.js   # создаёт app.js.br

Nginx

# nginx раздаёт предсжатые файлы
gzip_static on;      # ищет .gz рядом с файлом
brotli_static on;    # ищет .br рядом с файлом

Настройка в Express:

JavaScript
import express from 'express';
import compression from 'compression';

const app = express();

// Базовое сжатие (gzip по умолчанию)
app.use(compression({
      level: 6,
      threshold: 1024,  // не сжимать ответы меньше 1 KB
      filter: (req, res) => {

        // Не сжимать уже сжатые форматы
        const contentType = res.getHeader('Content-Type') || '';
        if (/image| video |audio/.test(contentType)) return false;
        return compression.filter(req, res);
      },
    }));

// Для Brotli в Express нужен shrink-ray-current или iltorb
import shrinkRay from 'shrink-ray-current';

app.use(shrinkRay({
      brotli: { quality: 4 }, // на лету -- ниже уровень для скорости
    }));

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

JavaScript
Файл: React bundle (500 KB)
-----------------------------------------
Без сжатия:  500 KB  (100%)
gzip -6:     145 KB  (29%)    быстро
gzip -9:     140 KB  (28%)    чуть медленнее
Brotli -4:   130 KB  (26%)    сравнимо с gzip по скорости
Brotli -11:  115 KB  (23%)    медленно, только для статики

📌 Реальные кейсы

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

JavaScript
// Проверяем, сжимается ли ресурс
const resources = performance.getEntriesByType('resource');

for (const res of resources) {
  if (res.decodedBodySize > 0 && res.transferSize > 0) {
    const ratio = 1 - res.encodedBodySize / res.decodedBodySize;
    const isCompressed = ratio > 0.1; // сжатие больше 10%

    if (!isCompressed && res.decodedBodySize > 10_000) {
      console.warn(
        `Несжатый ресурс (${(res.decodedBodySize / 1024).toFixed(0)} KB): ${res.name}`
      );
    }
  }
}

Webpack-плагин для предсжатия:

JavaScript
// webpack.config.js
import CompressionPlugin from 'compression-webpack-plugin';
import zlib from 'zlib';

export default {
  plugins: [
    // gzip
    new CompressionPlugin({
        filename: '[path][base].gz',
        algorithm: 'gzip',
        test: /\.(js| css |html| svg |json)$/,
        threshold: 1024,
        minRatio: 0.8,
      }),

    // Brotli
    new CompressionPlugin({
        filename: '[path][base].br',
        algorithm: 'brotliCompress',
        test: /\.(js| css |html| svg |json)$/,
        compressionOptions: { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 } },
        threshold: 1024,
        minRatio: 0.8,
      }),
  ],
};

Резюме

Сжатие -- одна из самых простых и эффективных оптимизаций. Brotli сжимает лучше gzip на 15-25% для текста. Для статических файлов используй предварительное сжатие на максимальном уровне (Brotli 11), для динамических -- сжатие на лету с умеренным уровнем (Brotli 4-6). Не сжимай изображения, видео и другие бинарные форматы -- они уже сжаты.

Как работает сжатие ответов (gzip, Brotli)? | JScriptiser