Невозможно отключить кодирование передачи по частям в nginx с помощью gzip для статических ресурсов, обслуживаемых серверной частью Node.

У нас есть веб-приложение Node/express, которое обслуживает статические ресурсы в дополнение к обычному контенту через express.static(). Перед ним находится nginx сервер, который в настоящее время настроен на gzip эти запросы статических активов, если user agent готов для этого.

Однако, хотя nginx выполняет gzip, как и ожидалось, он удаляет заголовок Content-Length из источника и вместо этого устанавливает Transfer-Encoding: chunked. Это нарушает кеширование нашего файла CDN.

Ниже приведены ответы на типичный запрос статического актива (в данном случае файл JS), от серверной части узла и от nginx:

Запрос:

curl -s -D - 'http://my_node_app/res/my_js.js' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Connection: keep-alive' --compressed -o /dev/null

Заголовки ответа от узла:

HTTP/1.1 200 OK
Accept-Ranges: bytes
Date: Wed, 07 Jan 2015 02:24:55 GMT
Cache-Control: public, max-age=0
Last-Modified: Wed, 07 Jan 2015 01:12:05 GMT
Content-Type: application/javascript
Content-Length: 37386   // <--- The expected header
Connection: keep-alive

Заголовки ответа от nginx:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 07 Jan 2015 02:24:55 GMT
Content-Type: application/javascript
Transfer-Encoding: chunked  // <--- The problematic header
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: public, max-age=0
Last-Modified: Wed, 07 Jan 2015 01:12:05 GMT
Content-Encoding: gzip

Наша текущая конфигурация nginx для статических ресурсов location выглядит следующим образом:

Конфигурация nginx:

# cache file paths that start with /res/
location /res/ {
    limit_except GET HEAD { }

    # http://nginx.com/resources/admin-guide/caching/
    # http://nginx.org/en/docs/http/ngx_http_proxy_module.html

    proxy_buffers 8 128k;
    #proxy_buffer_size 256k;
    #proxy_busy_buffers_size 256k;

    # The cache depends on proxy buffers, and will not work if proxy_buffering is set to off.
    proxy_buffering     on;
    proxy_http_version  1.1;
    proxy_set_header  Connection "";
    proxy_connect_timeout  2s;
    proxy_read_timeout  5s;
    proxy_pass          http://node_backend;

    chunked_transfer_encoding off;

    proxy_cache         my_app;
    proxy_cache_valid   15m;
    proxy_cache_key     $uri$is_args$args;
}

Как видно из приведенной выше конфигурации, несмотря на то, что мы явно установили chunked_transfer_encoding off для таких путей в соответствии с документами nginx, имеем proxy_buffering on и достаточно большое proxy_buffers size, ответ все еще разбивается на части.

Что нам здесь не хватает?

--Редактировать 1: информация о версии--

$ nginx -v
nginx version: nginx/1.6.1

$ node -v
v0.10.30

--Изменить 2: nginx конфигурация gzip--

# http://nginx.org/en/docs/http/ngx_http_gzip_module.html
gzip on;
gzip_buffers 32 4k;
gzip_comp_level 1;
gzip_min_length 1000;
#gzip_http_version 1.0;
gzip_types application/javascript text/css
gzip_proxied any;
gzip_vary on;

person kodeninja    schedule 07.01.2015    source источник
comment
Где вы говорите nginx для gzip? Он выполняет потоковое gzip, для которого единственным разумным вариантом является фрагментация. Вместо этого вы должны иметь статические ресурсы в необработанном и сжатом виде и настроить nginx для обслуживания сжатых ресурсов по запросу. Другими словами, pre gzip вместо gzip на лету.   -  person generalhenry    schedule 08.01.2015
comment
@generalhenry Я также добавил конфигурацию gzip. Вы правы, активы архивируются на лету. Я также видел модуль gzip_static, который помогает делать то, что вы описали. Так что, я думаю, в нашем случае нам придется либо разместить сырые + сжатые ресурсы на самом nginx, настроить gzip_static, и тогда он сделает все правильно. Или сделайте их предварительно созданными на этапе создания активов в Node, создайте некоторые умные устройства поверх express.static(), чтобы обслуживать одно или другое в зависимости от текущего запроса, и отключите gzip на nginx.   -  person kodeninja    schedule 08.01.2015
comment
Да gzip_proxyed любой; похоже, виноват (отказ от ответственности, я совсем не эксперт по nginx, я просто думаю с точки зрения потоков)   -  person generalhenry    schedule 08.01.2015
comment
Здравствуйте, Есть успехи в этом? Мы также сталкиваемся с той же проблемой.   -  person iMOBDEV    schedule 24.09.2015
comment
У меня такая же проблема serverfault.com/questions/745153/, и я также попробовал gzip на nginx и chunked_transfer_encoding off и установил заголовок в node.js res.header('transfer-encoding', ''); res.header('Content-Length', 0); все это не работает...   -  person user1575921    schedule 24.12.2015


Ответы (1)


Вы правы, позвольте мне уточнить.

Заголовки — это первое, что нужно отправить. Однако, поскольку вы используете потоковое сжатие, окончательный размер неизвестен. Вы знаете только размер несжатого ресурса, и отправка слишком большого Content-Length также будет неправильной.

Таким образом, есть два варианта:

  1. кодирование передачи по частям
  2. Полностью сжать ресурс перед отправкой каких-либо данных, чтобы был известен сжатый размер.

В настоящее время вы испытываете первый случай, и похоже, что вам действительно нужен второй. Самый простой способ получить второй случай — включить gzip_static, как сказал @kodeninja в комментариях.

person EnabrenTane    schedule 03.03.2016