Настройка gzip_min_length для буферизованных чанковых запросов от upstream в Nginx

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

У меня есть 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_request_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_min_length корректной для буферизованных запросов с использованием Transfer-Encoding: chunked, необходимо учесть нюансы работы Nginx при проксировании ответов от upstream-сервера. Поскольку в данном случае Nginx по умолчанию работает с буферизацией ответов, вы можете воспользоваться опцией proxy_buffering, которая в сочетании с proxy_pass может помочь правильно обрабатывать ответ от upstream-сервера.

Вот шаги, которые нужно выполнить:

  1. Включить буферизацию: Убедитесь, что у вас включена буферизация. По умолчанию, proxy_request_buffering включен, и это хорошо, так как Nginx будет обрабатывать ответ, прежде чем отправлять его клиенту.

  2. Добавьте параметры буферизации: Убедитесь, что все настройки, касающиеся буферов, установлены. Например, вы можете настроить proxy_buffers и proxy_buffer_size в зависимости от вашего сценария.

  3. Используйте gzip_proxied: Убедитесь, что параметр gzip_proxied установлен таким образом, чтобы включать gzip-компрессию для всех типов запросов (включая те, которые используют Transfer-Encoding: chunked).

  4. Оптимизация вашего конфигурационного файла Nginx: Ваши настройки могут выглядеть следующим образом:

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

    # Настройки gzip
    gzip on;
    gzip_types application/json;
    gzip_min_length 1000;
    gzip_proxied any;  # Включаем gzip для всех проксируемых запросов

    # Настройки буферизации ответа
    proxy_buffering on;  # Включаем буферизацию
    proxy_buffers 16 4k; # Настройте под потребности вашего приложения
    proxy_buffer_size 8k; # Настройте под потребности вашего приложения
}
  1. Проверка: После внесения изменений не забудьте перезапустить Nginx и протестировать оба эндпоинта (/api/bulk_get и /api/changes). Проверьте, что в ответах от Nginx для /api/changes устанавливается Content-Length и gzip используется только для ответов, размер которых превышает установленный вами порог в 1000 байт.

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

Если у вас остались вопросы или возникли проблемы с конфигурацией, не стесняйтесь обращаться за дополнительной помощью.

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

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