Nginx elimina el encabezado Content-Length para contenido fragmentado

10

Yo uso nginx 1.2.3 para proxy a un script:

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

Los scripts envían ambos Transfer-encoding: chunkedy Content-Length: 251:

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

Necesito ambos, pero nginx elimina automáticamente el 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: /...

Como resultado, los clientes no esperan a que se envíen los fragmentos. Esto solía funcionar con una versión anterior de nginx.

Julien
fuente
¿Cómo son los encabezados del proxy nginx?
cazando
¿con qué versión solía trabajar?
Cnst
Solía ​​funcionar con nginx 0.9.8
Julien
Estás violando el protocolo HTTP. Funciona con nginx 0.9.8, porque hasta la versión 1.1.4 no admite codificación fragmentada en absoluto.
VBart

Respuestas:

11

Desafortunadamente, no puedo comentar sobre la publicación de cnst, así que voy a responder aquí.

El nginx_http_proxymódulo por defecto habla con el upstream en HTTP / 1.0. Esto se puede cambiar con la directiva proxy_http_version 1.1.

Esta también podría ser la causa de que su script devuelva una respuesta HTTP / 1.0, aunque la codificación fragmentada y el código de estado 307no existen en esta versión.

Tampoco debe usar la codificación fragmentada con una redirección , ya que esto realmente no tiene sentido.

Además , parece que nginx no pasa trozos del flujo ascendente al cliente uno por uno, pero amortigua la respuesta del flujo ascendente . El Content-Lengthcampo de encabezado se ignora porque está en contra de la definición. Tuve que mirar el código fuente del módulo porque todo esto parece no estar documentado.

Es posible que desee probar el nginx_tcp_proxy_moduleproxy del contenido fragmentado como datos TCP sin procesar: Módulo en Github


ACTUALIZACIÓN (10.04.14)
El nginx_http_proxymódulo tiene soporte para X-Accel-* encabezados , de los cuales uno ( X-Accel-Buffering: yes|no) controla si la respuesta debe ser almacenada o no.

Agregar este encabezado ( X-Accel-Buffering: no) a la respuesta del backend hará que nginx pase directamente fragmentos al cliente.

Este encabezado permite controlar el almacenamiento en búfer por solicitud .

El módulo también tiene una directiva de configuración proxy_buffering para habilitar o deshabilitar el almacenamiento en búfer de respuesta (no almacenar en búfer significa que el envío de fragmentos funcionará).

El búfer de proxy (basado tanto en encabezado como en directivas) se documenta aquí .

Lukas
fuente
No debería hacer eso incluso con nginx_tcp_proxy_module. Funciona con algunos navegadores solo porque son muy tolerantes a errores.
VBart
porque todo esto parece ser indocumentado Incorrecto. Está documentado en RFC 2616. Ver 13.5.1 .
VBart
@VBart Claro que hay estándares, pero solo hay muy poca información sobre hasta qué punto los implementa particularmente nginx . El módulo proxy TCP es una solución alternativa sugerida .
Lukas
9

Como Lukas alude, HTTP 1.1 prohíbe Content-Lengthsi hay un Transfer-Encodingconjunto.

Citando 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.
Jo Liss
fuente
Además, el comportamiento correcto de Nginx en conformidad con HTTP 1.1 contribuye en gran medida a prevenir ataques de contrabando de solicitudes HTTP .
amn
3

En primer lugar, no ha explicado específicamente por qué su script necesita codificación fragmentada, especialmente con una respuesta de redireccionamiento.

Veo una multitud de problemas aquí.

  • Transfer-Encoding: chunkedes una HTTP/1.1función (y su script parece estar respondiendo con un HTTP/1.0encabezado)

  • no hay 307enHTTP/1.0

  • el propósito de esto chunkedes que no sabes cuál Content-Lengthhubiera sido tu, por lo tanto, chunkedse usa en lugar de proporcionar la longitud dentro Content-Length, donde las longitudes se proporcionan dentro del cuerpo de la respuesta, entremezcladas con el contenido real; no tendría sentido que un script genere ambos encabezados por adelantado

No estoy familiarizado personalmente chunked, pero según la información básica en http://en.wikipedia.org/wiki/Chunked_transfer_encoding y también http://tools.ietf.org/html/rfc2616#section-3.6.1 , Supongo que el manejo completo de la secuencia de comandos de la codificación fragmentada puede ser completamente incorrecto.

Si lo anterior aún no lo cubre, y en realidad de lo contrario, tampoco está claro por qué una respuesta con un código de estado 307o 302http debe proporcionarse con una codificación "extraña". Recientemente hubo una discusión similar en la lista de correo de nginx 410 Goney otras páginas de error siempre excluidas de la gzipcompresión, y creo que el sentimiento se aplicaría igualmente aquí. ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )

cnst
fuente
Lo utilizo para hacer que el usuario espere: envío fragmentos cada segundos, de modo que el usuario esperará la redirección durante X segundos sin que se agote el tiempo de espera
Julien
Yo te aconsejo que primero HTTP / corrección de 1,0 a HTTP / 1.1 (estas cosas hacen una diferencia), y asegúrese de que la codificación fragmentada no es inadecuada. La versión más nueva de nginx probablemente descarta algunos encabezados de los que depende porque están equivocados.
Cnst
1

Tuve el mismo problema al transmitir archivos mp4 a través de la etiqueta de video html5.

Safari y Firefox se comportaron normalmente mientras que Chrome estaba activando ERR_CONTENT_LENGTH_MISMATCH en algún momento (pero me permitió ver varios minutos del video antes de fallar).

El problema no se reprodujo después de que apagué el control de caché para archivos mp4.

Buzut
fuente
0

Compartiendo esta respuesta, publiqué en SO en caso de que sea útil: /programming/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

Tuve un problema similar con la reproducción de mp4 debido a que no se sirvieron fragmentos, y confirmó el problema según la guía de Apple, que se enumera a continuación. Verifiqué que estaba descargando todo el archivo, y después de la corrección a continuación, solo el primer fragmento.

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

Resolví mi reproducción de Safari .mp4 cambiando mi configuración de compresión gzip en mi nginx.conf, para eliminar la compresión gzip de archivos .mp4 .

Aquí está el bloque en nginx para referencia. (Nota: dependiendo de cómo esté configurada su aplicación, es posible que deba cambiar la línea de ubicación alocation ~ \.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;
}

Enlace a la referencia de documentación de Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-SW6

Kelton.Temby
fuente