Сделайте “gzip_min_length” в Nginx рабочим для буферизованных пониженных запросов от upstream.

Вопрос или проблема

У меня есть upstream-сервер, который я не могу изменить, который предоставляет два маршрута:

  • /api/bulk_get
    • возвращает некоторый JSON-контент
    • знает длину ответа, поэтому устанавливает Content-Length соответственно
  • /api/changes
    • возвращает некоторый JSON-контент
    • использует Transfer-Encoding: chunked так как длина ответа заранее не известна, поэтому Content-Length не может быть установлен

Сервер слушает на порту 2626.

Это затем передается через Nginx (v1.20.x), использующийся как обратный прокси:

location /api {
    rewrite /api/(.*) /$1 break;
    proxy_pass http://localhost:2626;
    proxy_redirect off;
    proxy_set_header Host $host;

    gzip on;
    gzip_types application/json;
    gzip_min_length 1000;
}
  • Для маршрута /api/bulk_get Content-Length известен, поэтому gzip_min_length работает нормально.
  • Для маршрута /api/changes Content-Length отсутствует, поэтому gzip_min_length не соблюдается и все запросы сжимаются.

Дело в том, что Nginx буферизует ответы от upstream-сервера (так как proxy_buffering включен по умолчанию), поэтому он знает размер ответа.

Чтобы схематизировать, у нас есть

upstream ------------------------> nginx reverse proxy ---------------------> client
        Transfer-Encoding: chunked                      no Transfer-Encoding
                                   buffers the chunks                  receive several chunks at once

Как я могу настроить прокси, чтобы Content-Length вычислялся по буферизированному ответу, заставляя gzip_min_length работать для маршрута /api/changes?

Ответ или решение

Для решения вашей проблемы с компрессией Gzip в Nginx для маршрута /api/changes, необходимо учитывать некоторые ключевые моменты, касающиеся буферизации и обработки заголовков ответа. Несмотря на то, что вы не можете изменять сервер, работающий на порту 2626, Nginx может быть настроен так, чтобы его конфигурация правильно работала с ответами, использующими Transfer-Encoding: chunked.

Проблема

Ваша текущая конфигурация Nginx позволяет сжатие Gzip применять правильно, если сервер возвращает значение Content-Length. Однако когда ответ приходит с использованием Transfer-Encoding: chunked, заголовок Content-Length отсутствует и Nginx не создает значение Content-Length для определённых настроек, таких как gzip_min_length, что приводит к тому, что все ответы сжимаются, даже если их длина меньше 1000 байт.

Рекомендации по настройкам Nginx

Чтобы обойти это ограничение, можно воспользоваться следующими шагами:

  1. Включите буферизацию и настройте максимальные размеры буферов:
    Вам нужно убедиться, что как минимум один из следующих параметров настроен для обработки буферизации ответов.

    proxy_buffering on;  # Буферизация включена, по умолчанию включена
    proxy_buffer_size 128k;  # Установите размер буфера
    proxy_buffers 4 256k;  # Задайте количество и размер буферов
    proxy_busy_buffers_size 256k;  # Убедитесь, что сжатие может работать эффективно
  2. Настройка gzip с использованием заголовков:
    Убедитесь, что gzip_min_length работает должным образом, добавив следующую настройку:

    gzip_proxied any;  # Позволяет Gzip на проксированных ответах
    gzip_min_length 1000;  # Указанная минимальная длина

    Эти параметры обеспечат, что сжатие применяется, когда размер ответа превышает указанный минимальный порог.

  3. Использование proxy_pass корректно:
    Ваш код уже настроен правильно с использованием proxy_pass. Также убедитесь, что следующий флаг прокси не мешает:

    proxy_set_header Accept-Encoding "";  # Это отключает сжатие от клиента

    Это гарантирует, что ответ сжат Nginx, а не передается клиенту с учетом его предпочтений.

Исправленная конфигурация

Вот пример полной конфигурации для вашего сценария:

location /api {
    rewrite /api/(.*) /$1 break;
    proxy_pass http://localhost:2626;
    proxy_redirect off;
    proxy_set_header Host $host;

    # Настройка буферов
    proxy_buffering on;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;

    # Настройка Gzip
    gzip on;
    gzip_types application/json;
    gzip_proxied any;  # Убедитесь, что Gzip включен для проксированных ответов
    gzip_min_length 1000;  # Минимальная длина ответа для сжатия
}

Заключение

С вышеуказанными изменениями, Nginx будет правильно обрабатывать и сжимать ответы от вашего upstream сервера, даже если они возвращаются с использованием Transfer-Encoding: chunked. Важным аспектом работы с Nginx является правильная настройка буферизации и компрессии, что позволяет уменьшить объем передаваемых данных и повысить производительность вашего приложения.

Оцените материал
Добавить комментарий

Капча загружается...