Вопрос или проблема
У меня есть 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
Чтобы обойти это ограничение, можно воспользоваться следующими шагами:
-
Включите буферизацию и настройте максимальные размеры буферов:
Вам нужно убедиться, что как минимум один из следующих параметров настроен для обработки буферизации ответов.proxy_buffering on; # Буферизация включена, по умолчанию включена proxy_buffer_size 128k; # Установите размер буфера proxy_buffers 4 256k; # Задайте количество и размер буферов proxy_busy_buffers_size 256k; # Убедитесь, что сжатие может работать эффективно
-
Настройка gzip с использованием заголовков:
Убедитесь, чтоgzip_min_length
работает должным образом, добавив следующую настройку:gzip_proxied any; # Позволяет Gzip на проксированных ответах gzip_min_length 1000; # Указанная минимальная длина
Эти параметры обеспечат, что сжатие применяется, когда размер ответа превышает указанный минимальный порог.
-
Использование
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 является правильная настройка буферизации и компрессии, что позволяет уменьшить объем передаваемых данных и повысить производительность вашего приложения.