Назад | Перейти на главную страницу

Nginx удаляет заголовок Content-Length для фрагментированного содержимого

Я использую nginx 1.2.3 для прокси к скрипту:

proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8880;
proxy_buffering off;
proxy_read_timeout 300s;
gzip off;

Скрипты отправляют оба Transfer-encoding: chunked и Content-Length: 251:

HTTP/1.0 307 Temporary Redirect
Content-length: 251
Pragma: no-cache
Location: /...
Cache-control: no-cache
Transfer-encoding: chunked

Мне нужны оба, но nginx автоматически удаляет Content-Length:

HTTP/1.1 302 Found
Server: nginx/1.2.3
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Location: /...

В результате клиенты не ждут отправки чанков. Раньше это работало с более ранней версией nginx.

К сожалению, я не могу комментировать сообщение cnst - поэтому отвечу здесь.

В nginx_http_proxy модуль по умолчанию общается с восходящим потоком в HTTP / 1.0. Это можно изменить с помощью директивы proxy_http_version 1.1.

Это также может быть причиной того, что ваш скрипт возвращает ответ HTTP / 1.0, хотя кодирование фрагментов и код состояния 307 не существует в этой версии.

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

Дополнительно, похоже, nginx не пропускает куски от восходящего потока к клиенту один за другим, но он буферизует ответ восходящего потока. В Content-Length поле заголовка игнорируется, потому что оно противоречит определению. Я должен был посмотреть на исходный код модуля, потому что все это кажется недокументированным.

Вы можете попробовать nginx_tcp_proxy_module для проксирования фрагментированного содержимого как необработанных данных TCP: Модуль на Github


ОБНОВИТЬ (10.04.14)
The nginx_http_proxy module has support for X-Accel-* заголовки, of which one (X-Accel-Buffering: yes|no) controls whether the response should be buffered or not.

Добавление этого заголовка (X-Accel-Buffering: no) в ответ серверной части заставит nginx напрямую передавать фрагменты клиенту.

Этот заголовок позволяет управлять буферизацией на по запросу.

Модуль также имеет директива конфигурации proxy_buffering для включения или отключения буферизации ответа (без буферизации означает, что отправка фрагментов будет работать).

Буферизация прокси (как на основе заголовков, так и директив) задокументирована. Вот.

Как сказал Лукас, HTTP 1.1 запрещает Content-Length если есть Transfer-Encoding устанавливать.

Цитирование http://www.ietf.org/rfc/rfc2616.txt:

   3.If a Content-Length header field (section 14.13) is present, its
     decimal value in OCTETs represents both the entity-length and the
     transfer-length. The Content-Length header field MUST NOT be sent
     if these two lengths are different (i.e., if a Transfer-Encoding
     header field is present). If a message is received with both a
     Transfer-Encoding header field and a Content-Length header field,
     the latter MUST be ignored.

Вы конкретно не объяснили, почему вашему скрипту в первую очередь нужна фрагментированная кодировка, особенно с ответом на перенаправление.

Я вижу здесь множество проблем.

  • Transfer-Encoding: chunked является HTTP/1.1 функция (и ваш скрипт, кажется, отвечает HTTP/1.0 заголовок)

  • здесь нет 307 в HTTP/1.0

  • вся цель chunked это то, что ты не знаешь, что твое Content-Length было бы так, chunked используется вместо указания длины в пределах Content-Length, где вместо этого длины указываются в теле ответа, смешанного с фактическим содержанием; было бы бессмысленно для сценария генерировать оба заголовка заранее

Я лично не знаком с chunked, но согласно основной информации на http://en.wikipedia.org/wiki/Chunked_transfer_encoding а также http://tools.ietf.org/html/rfc2616#section-3.6.1, Я бы предположил, что вся обработка вашего скрипта фрагментированной кодировки может быть совершенно неправильной.

Если вышеупомянутое все еще не покрывает это, а на самом деле иначе, также неясно, почему ответ с 307 или 302 Код состояния http должен быть предоставлен в "странной" кодировке. Недавно в списке рассылки nginx было аналогичное обсуждение 410 Gone и другие страницы ошибок всегда исключаются из gzip сжатие, и я думаю, что это чувство также применимо и здесь. (http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html)

У меня была такая же проблема с потоковой передачей файла mp4 через тег видео html5.

Safari и Firefox вели себя нормально, тогда как Chrome в какой-то момент запускал ERR_CONTENT_LENGTH_MISMATCH (но это позволило мне просмотреть несколько минут видео до сбоя).

Проблема не воспроизводилась после того, как я отключил управление кешем для файлов mp4.

Поделившись этим ответом, который я отправил в SO, если он будет полезен: https://stackoverflow.com/questions/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

У меня была аналогичная проблема с воспроизведением mp4 из-за того, что фрагменты не обслуживаются, и я подтвердил проблему в соответствии с руководством Apple, указанным ниже. Я подтвердил, что загружаю весь файл, а после исправления ниже только первый фрагмент.

curl --range 0-99 http://example.com/test.mov -o /dev/null

Я разрешил воспроизведение файлов Safari .mp4, изменив настройки сжатия gzip в моем nginx.conf, чтобы удалить сжатие gzip для .mp4 файлы.

Вот блок в nginx для справки. (Примечание: в зависимости от того, как настроено ваше приложение, вам может потребоваться изменить строку местоположения на location ~ \.mp4$ {

location ~ ^/(assets|system|videos)/  {
   expires max;
   add_header Cache-Control public;
   add_header ETag "";
   gzip on;
   gzip_http_version 1.1;
   gzip_vary on;
   gzip_comp_level 6;
   gzip_proxied any;

   # Reference configuration
   #gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript video/mp4 application/mp4 image/jpeg image/png image/svg+xml application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;

   # Kelton trying to fix cloudflare by removing the mp4 settings
   gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript image/jpeg image/png image/svg+xml application/application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
}

Ссылка на справочную документацию Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-SW6