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


10

Я використовую 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.


Як виглядають заголовки проксі-сервера nginx?
hrunting

з якою версією вона працювала?
cnst

Раніше він працював з nginx 0.9.8
Жульєн

Ви порушуєте протокол HTTP. Він працює з nginx 0.9.8, оскільки до версії 1.1.4 він взагалі не підтримує чітке кодування.
VBart

Відповіді:


11

На жаль, я не можу коментувати публікацію 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) модуль має підтримку для заголовків , один з яких ( ) визначає , буде чи відповідь повинен бути буферизованного чи ні.
nginx_http_proxyX-Accel-* X-Accel-Buffering: yes|no

Додавання цього заголовка ( X-Accel-Buffering: no) до відповіді бекенда призведе до того, що nginx безпосередньо передає фрагменти клієнту.

Цей заголовок дозволяє контролювати буферизацію на основі запиту .

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

Проксі - буферизація (як заголовок і директива основі) документований тут .


Він не повинен цього робити навіть nginx_tcp_proxy_module. Він працює з деякими браузерами лише тому, що вони дуже терплячі до помилок.
VBart

тому що все це видається недокументованим Неправильно. Це описано в RFC 2616. Див 13.5.1 .
VBart

@VBart Звичайно, є стандарти - але є лише дуже мало інформації про те, наскільки конкретно nginx їх реалізує. TCP-проксі-модуль має бути запропонованим способом вирішення .
Лукас

9

Як Лукас наголошує, 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.

Крім того, правильна поведінка Nginx у дотриманні HTTP 1.1 проходить довгий шлях до запобігання атакам контрабанди запитів HTTP .
amn

3

Ви спеціально не роз'яснювали, чому ваш сценарій потребує першочергового кодування, особливо з відповіддю на переадресацію.

Я бачу тут безліч проблем.

  • 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або 302http має бути забезпечена "дивним" кодуванням. Нещодавно відбулося подібне обговорення в списку розсилки nginx про 410 Goneта інші сторінки помилок, які завжди виключаються зі gzipстиснення, і я думаю, що настрої також однаково стосуватимуться тут. ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )


Я використовую його, щоб змусити користувача чекати: я надсилаю шматки кожні секунди, щоб користувач чекав перенаправлення протягом X секунд, не отримуючи тайм-аут
Жульєн

Я б порадив Вам спочатку виправити HTTP / 1.0 до HTTP / 1.1 (ці речі роблять зробити різницю), і переконайтеся , що Chunked кодування не непристойним. Більш нова версія nginx, ймовірно, відкидає деякі заголовки, від яких ви залежите, оскільки вони помиляються.
cnst

1

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

Safari та Firefox поводилися нормально, тоді як Chrome в якийсь момент спрацьовував ERR_CONTENT_LENGTH_MISMATCH (але це дозволило мені відібрати кілька хвилин відео, перш ніж вийти з ладу).

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


0

Ділячись цією відповіддю, я опублікував повідомлення на випадок, якщо це корисно: /programming/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

Я вирішив відтворення .f4 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-WW

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.