Nginx rimuove l'intestazione Content-Length per il contenuto in blocchi


10

Uso nginx 1.2.3 come proxy per uno script:

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

Gli script invia sia Transfer-encoding: chunkede Content-Length: 251:

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

Ho bisogno di entrambi, ma nginx rimuove automaticamente 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: /...

Di conseguenza, i client non attendono l'invio dei blocchi. In passato funzionava con una versione precedente di nginx.


Che aspetto hanno le intestazioni dal proxy nginx?
caccia il

con quale versione funzionava?
primo

Lavorava con nginx 0.9.8
Julien

Stai violando il protocollo HTTP. Funziona con nginx 0.9.8, perché fino alla versione 1.1.4 non supporta affatto la codifica chunked.
Vart

Risposte:


11

Sfortunatamente, non posso commentare il post di cnst, quindi risponderò qui.

Il nginx_http_proxymodulo di default parla con l'upstream in HTTP / 1.0. Questo può essere modificato con la direttiva proxy_http_version 1.1.

Questo potrebbe anche essere il motivo per cui lo script restituisce una risposta HTTP / 1.0, sebbene 307in questa versione non esistano codifica a blocchi e codice di stato .

Non dovresti nemmeno usare la codifica a blocchi con un reindirizzamento , poiché questo non ha davvero senso.

Inoltre , sembra che nginx non passi i blocchi dall'upstream al client uno per uno, ma bufferizza la risposta dell'upstream . Il Content-Lengthcampo di intestazione viene ignorato perché è contrario alla definizione. Ho dovuto guardare il codice sorgente del modulo perché tutto ciò sembra essere privo di documenti.

Puoi provare a eseguire il nginx_tcp_proxy_moduleproxy del contenuto in blocchi come dati TCP non elaborati: Modulo su Github


AGGIORNAMENTO (10.04.14)
Il nginx_http_proxymodulo ha il supporto per le X-Accel-* intestazioni , di cui una ( X-Accel-Buffering: yes|no) controlla se la risposta deve essere bufferizzata o meno.

L'aggiunta di questa intestazione ( X-Accel-Buffering: no) alla risposta del backend farà sì che nginx passi direttamente i blocchi al client.

Questa intestazione consente di controllare il buffering in base alla richiesta .

Il modulo ha anche una direttiva di configurazione proxy_buffering per abilitare o disabilitare il buffering di risposta (non buffering significa che l'invio di blocchi funzionerà).

Il buffering proxy (sia basato su intestazione sia su direttiva) è documentato qui .


Non dovrebbe farlo nemmeno con nginx_tcp_proxy_module. Funziona con alcuni browser solo perché sono molto tolleranti agli errori.
Vart

perché tutto ciò sembra essere privo di documenti Wrong. È documentato in RFC 2616. Vedi 13.5.1 .
VBart

@VBart Sicuramente ci sono degli standard, ma ci sono solo pochissime informazioni su come in particolare nginx li implementa. Il modulo proxy TCP è una soluzione suggerita .
Lukas,

9

Come Lukas allude, HTTP 1.1 vieta Content-Lengthse esiste un Transfer-Encodingset.

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.

Inoltre, il comportamento corretto di Nginx in conformità con HTTP 1.1 aiuta molto a prevenire attacchi di contrabbando di richieste HTTP .
AMN

3

Non hai specificamente spiegato perché la tua sceneggiatura abbia bisogno di una codifica in blocco, in primo luogo, specialmente con una risposta di reindirizzamento.

Vedo una moltitudine di problemi qui.

  • Transfer-Encoding: chunkedè una HTTP/1.1funzione (e il tuo script sembra rispondere con HTTP/1.0un'intestazione)

  • non c'è 307dentroHTTP/1.0

  • lo scopo chunkedè di non sapere quale Content-Lengthsarebbe stato il tuo, quindi chunkedviene usato al posto di fornire la lunghezza all'interno Content-Length, dove invece le lunghezze sono fornite all'interno del corpo della risposta, mescolate al contenuto effettivo; sarebbe inutile per uno script generare entrambe le intestazioni in anticipo

Non conosco personalmente chunked, ma secondo le informazioni di base su http://en.wikipedia.org/wiki/Chunked_transfer_encoding e anche http://tools.ietf.org/html/rfc2616#section-3.6.1 , Immagino che l'intera gestione della codifica in blocchi della tua sceneggiatura possa essere completamente sbagliata.

Se quanto sopra ancora non lo copre, e in tutta la realtà altrimenti, non è anche chiaro perché una risposta con un codice di stato 307o 302http dovrebbe essere fornita con una codifica "strana". Recentemente c'è stata una discussione simile nella mailing list di nginx 410 Gonee altre pagine di errore sono sempre state escluse dalla gzipcompressione, e penso che il sentimento si applicherebbe ugualmente qui. ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )


Lo uso per far aspettare l'utente: invio blocchi ogni secondo, in modo che l'utente attenda il reindirizzamento per X secondi senza ottenere un timeout
Julien

Io vi consiglio di primo fix HTTP / 1.0 a HTTP / 1.1 (queste cose fanno la differenza), e assicurarsi che le codifica Chunked non è improprio. La versione più recente di nginx probabilmente scarta alcune intestazioni dalle quali dipendi perché sbagliate.
primo

1

Ho avuto lo stesso problema con lo streaming di file mp4 tramite tag video html5.

Safari e Firefox si sono comportati normalmente mentre Chrome stava attivando ERR_CONTENT_LENGTH_MISMATCH ad un certo punto (ma mi ha permesso di cancellare alcuni minuti del video prima di fallire).

Il problema non si è riprodotto dopo aver disattivato il controllo della cache per i file mp4.


0

Condividendo questa risposta ho pubblicato su SO nel caso sia utile: /programming/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

Ho avuto un problema simile con la riproduzione di mp4 a causa di blocchi non serviti e ho confermato il problema secondo la guida di Apple, elencata di seguito. Ho verificato che stavo scaricando l'intero file e, dopo la correzione di seguito, solo il primo pezzo.

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

Ho risolto la mia riproduzione .mp4 di Safari modificando le impostazioni di compressione gzip nel mio nginx.conf, per rimuovere la compressione gzip dei file .mp4 .

Ecco il blocco in nginx per riferimento. (Nota: a seconda della configurazione dell'app, potrebbe essere necessario modificare la linea di posizione inlocation ~ \.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;
}

Link alla documentazione di riferimento di Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/W000

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.