Nginx remove o cabeçalho Content-Length para conteúdo em pedaços

10

Eu uso o nginx 1.2.3 para fazer proxy de um script:

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

Os scripts enviam ambos 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

Eu preciso dos dois, mas o nginx remove automaticamente o 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, os clientes não esperam o envio dos pedaços. Isso costumava funcionar com uma versão anterior do nginx.

Julien
fonte
Como são os cabeçalhos do proxy nginx?
28513 hrunting
com qual versão ele costumava trabalhar?
CNST
Ele costumava trabalhar com o nginx 0.9.8
Julien '
Você está violando o protocolo HTTP. Ele funciona com o nginx 0.9.8, porque até a versão 1.1.4 ele não suporta codificação em partes.
VBart 30/09

Respostas:

11

Infelizmente, não posso comentar na postagem do cnst - por isso vou responder aqui.

O nginx_http_proxymódulo, por padrão, conversa com o upstream no HTTP / 1.0. Isso pode ser alterado com a diretiva proxy_http_version 1.1.

Isso também pode ser a causa do seu script retornar uma resposta HTTP / 1.0, embora a codificação em partes e o código de status 307não existam nesta versão.

Você também não deve usar a codificação em blocos com um redirecionamento , pois isso realmente não faz sentido.

Além disso , parece que o nginx não passa pedaços do upstream para o cliente um por um, mas armazena em buffer a resposta do upstream . O Content-Lengthcampo do cabeçalho é ignorado porque é contra a definição. Eu tive que olhar para o código fonte do módulo, porque tudo isso parece estar sem documentos.

Você pode experimentar o nginx_tcp_proxy_moduleproxy do conteúdo em blocos como dados TCP brutos: Módulo no Github


UPDATE (10.04.14)
O nginx_http_proxymódulo possui suporte para X-Accel-* cabeçalhos , dos quais um ( X-Accel-Buffering: yes|no) controla se a resposta deve ser armazenada em buffer ou não.

Adicionar este cabeçalho ( X-Accel-Buffering: no) à resposta do back-end fará com que o nginx passe diretamente os pedaços para o cliente.

Este cabeçalho permite controlar o buffer em uma base por solicitação .

O módulo também possui uma diretiva de configuração proxy_buffering para habilitar ou desabilitar o buffer de resposta (sem buffer significa que o envio de chunks funcionará).

O buffer de proxy (baseado em cabeçalho e diretiva) está documentado aqui .

Lukas
fonte
Ele não deveria fazer isso mesmo nginx_tcp_proxy_module. Ele funciona com alguns navegadores apenas porque são muito tolerantes a erros.
Vbart
porque tudo isso parece indocumentado errado. Está documentado na RFC 2616. Consulte 13.5.1 .
Vbart
@VBart Claro que existem padrões - mas há poucas informações sobre até que ponto o nginx os implementa.O módulo proxy TCP oferece uma solução alternativa sugerida .
Lukas
9

Como Lukas aludiu, o HTTP 1.1 proíbe Content-Lengthse houver um 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
fonte
Além disso, o comportamento correto do Nginx em conformidade com o HTTP 1.1 ajuda bastante na prevenção de ataques de contrabando de solicitação HTTP .
amn 14/03
3

Você não detalhou especificamente por que seu script precisa de codificação em partes, principalmente com uma resposta de redirecionamento.

Eu vejo uma infinidade de problemas aqui.

  • Transfer-Encoding: chunkedé um HTTP/1.1recurso (e seu script parece estar respondendo com um HTTP/1.0cabeçalho)

  • não existe 307emHTTP/1.0

  • o objetivo de todo chunkedé que você não sabe qual Content-Lengthteria sido, portanto, chunkedé usado no lugar de fornecer o comprimento interno Content-Length, onde os comprimentos são fornecidos no corpo da resposta, misturados com o conteúdo real; seria inútil que um script gere ambos os cabeçalhos antecipadamente

Não conheço pessoalmente chunked, mas de acordo com as informações básicas em http://en.wikipedia.org/wiki/Chunked_transfer_encoding e também http://tools.ietf.org/html/rfc2616#section-3.6.1 , Eu suponho que o manuseio completo da codificação em partes do seu script possa estar completamente errado.

Se o que foi dito acima ainda não o abordar, e em toda a atualidade, também não está claro por que uma resposta com um código de status 307ou 302http deve ser fornecida com uma codificação "estranha". Recentemente, houve uma discussão semelhante na lista de discussão nginx sobre 410 Gonee outras páginas de erro sempre excluídas da gzipcompactação, e acho que o sentimento se aplicaria igualmente aqui. ( http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html )

cnst
fonte
Eu usá-lo para fazer o usuário esperar: Eu enviar blocos a cada segundos, para que o usuário irá aguardar o redirecionamento para X segundos sem ficar um tempo limite
Julien
Eu aconselho você a primeira HTTP correção / 1.0 para HTTP / 1.1 (essas coisas fazer fazer a diferença), e certifique-se a sua codificação fragmentada não é impróprio. A versão mais recente do nginx provavelmente descarta alguns cabeçalhos dos quais você depende, porque eles estão errados.
CNST
1

Eu tive o mesmo problema de streaming de arquivo mp4 através da tag de vídeo html5.

O Safari e o Firefox se comportaram normalmente, enquanto o Chrome estava acionando o ERR_CONTENT_LENGTH_MISMATCH em algum momento (mas me permitiu assistir vários minutos do vídeo antes de falhar).

O problema não foi reproduzido depois que eu desliguei o controle de cache para arquivos mp4.

Buzut
fonte
0

Compartilhando esta resposta, publiquei na SO caso seja útil: /programming/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509

Eu tive um problema semelhante com a reprodução de mp4 devido à falta de veiculação de pedaços e confirmei o problema pelo guia da Apple, listado abaixo. Eu verifiquei que estava baixando o arquivo inteiro e, após a correção abaixo, apenas o primeiro pedaço.

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

Resolvi minha reprodução .mp4 do Safari alterando minhas configurações de compactação gzip no meu nginx.conf, para remover a compactação gzip dos arquivos .mp4 .

Aqui está o bloco no nginx para referência. (Observação: dependendo de como seu aplicativo está configurado, pode ser necessário alterar a linha de localização paralocation ~ \.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 para a referência de documentação da Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-Windows

Kelton.Temby
fonte