Вопрос или проблема
У меня есть 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-сервера.
Вот шаги, которые нужно выполнить:
-
Включить буферизацию: Убедитесь, что у вас включена буферизация. По умолчанию,
proxy_request_buffering
включен, и это хорошо, так как Nginx будет обрабатывать ответ, прежде чем отправлять его клиенту. -
Добавьте параметры буферизации: Убедитесь, что все настройки, касающиеся буферов, установлены. Например, вы можете настроить
proxy_buffers
иproxy_buffer_size
в зависимости от вашего сценария. -
Используйте
gzip_proxied
: Убедитесь, что параметрgzip_proxied
установлен таким образом, чтобы включать gzip-компрессию для всех типов запросов (включая те, которые используютTransfer-Encoding: chunked
). -
Оптимизация вашего конфигурационного файла 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; # Настройте под потребности вашего приложения
}
- Проверка: После внесения изменений не забудьте перезапустить Nginx и протестировать оба эндпоинта (
/api/bulk_get
и/api/changes
). Проверьте, что в ответах от Nginx для/api/changes
устанавливаетсяContent-Length
и gzip используется только для ответов, размер которых превышает установленный вами порог в 1000 байт.
С помощью приведенных выше настроек, приложения, работающие с Transfer-Encoding: chunked
, должны корректно поддерживать gzip_min_length
, так как Nginx будет знать окончательный размер ответа после его буферизации.
Если у вас остались вопросы или возникли проблемы с конфигурацией, не стесняйтесь обращаться за дополнительной помощью.