Transfer-Encoding: gzip vs. Content-Encoding: gzip

98

Qual é o estado atual das coisas quando se trata de fazer

Transfer-Encoding: gzip

ou um

Content-Encoding: gzip

quando desejo permitir que clientes com, por exemplo, largura de banda limitada, sinalizem sua disposição de aceitar uma resposta compactada e o servidor tenha a palavra final se deve compactar ou não .

O último é o que, por exemplo, o mod_deflate do Apache e o IIS fazem, se você permitir que ele cuide da compactação. Dependendo do tamanho do conteúdo a ser compactado, ele fará o adicional Transfer-Encoding: chunked.

Também incluirá um Vary: Accept-Encoding, que já indica o problema. Content-Encodingparece ser parte da entidade, portanto, alterar os Content-Encodingvalores para uma alteração da entidade, ou seja, um Accept-Encodingcabeçalho diferente significa, por exemplo, um cache não pode usar sua versão em cache da entidade idêntica de outra forma.

Existe uma resposta definitiva sobre isso que eu perdi (e que não está enterrada dentro de uma mensagem em uma longa discussão em algum grupo de notícias do Apache)?

Minha impressão atual é:

  • A codificação de transferência seria, de fato, a maneira certa de fazer o que geralmente é feito com a codificação de conteúdo pelas implementações existentes de servidor e cliente
  • A codificação de conteúdo, por causa de suas implicações semânticas, traz alguns problemas (o que o servidor deve fazer para ETagquando comprime uma resposta de forma transparente?)
  • O motivo é frango'n'egg: os navegadores não suportam porque os servidores não, porque os navegadores não

Portanto, estou assumindo que o caminho certo seria um Transfer-Encoding: gzip(ou, se eu adicionalmente dividir o corpo, ele se tornaria Transfer-Encoding: gzip, chunked ). E não há razão para tocar em Varyou ETagou qualquer outro cabeçalho nesse caso, pois é uma coisa de nível de transporte.

Por enquanto, não me importo muito com o 'salto a salto' de Transfer-Encoding, algo que os outros parecem estar preocupados em primeiro lugar, porque os proxies podem descompactar e encaminhar descompactado para o cliente. No entanto, os proxies podem muito bem encaminhá-lo no estado em que se encontra (compactado), se a solicitação original tiver o Accept-Encodingcabeçalho adequado , o que, no caso de todos os navegadores que conheço, é um dado adquirido.

A propósito, esse problema já existe há pelo menos uma década, consulte, por exemplo, https://bugzilla.mozilla.org/show_bug.cgi?id=68517 .

Qualquer esclarecimento sobre isso será apreciado. Tanto em termos do que é considerado compatível com os padrões quanto do que é considerado prático. Por exemplo, as bibliotecas de cliente HTTP que suportam apenas "Codificação de conteúdo" transparente seriam um argumento contra a praticidade.

Eugene Beresovksy
fonte
2
Relacionado: stackapps.com/questions/916/…
Jo Liss
Apenas corri para isso. Curl no PHP 5.3 não entende Transfer-Encoding:gzip, embora curl de linha de comando sim. Para ficar no lado seguro, envie ambos, a menos que você esteja combinando chunked e gzip.
Seva Alekseyev
1
@SevaAlekseyev enviar ambos seria muito errado - os clientes podem tentar descomprimir duas vezes
Joshua Wise
Isso é algo que também me incomoda para sempre ( pergunta que fiz ) ... por uma das respostas à pergunta que @JoLiss citou, há uma maneira perfeitamente lógica, semanticamente coerente e compatível com os padrões de compactar corpos de solicitação / resposta ... e basicamente nenhum cliente / servidor o usa ou oferece suporte. 🤦🏻‍
Dan Lenski

Respostas:

35

Citando Roy T. Fielding , um dos autores da RFC 2616:

alterar a codificação do conteúdo em tempo real de maneira inconsistente (nem "nunca" nem "sempre) torna impossível que solicitações posteriores relativas a esse conteúdo (por exemplo, PUT ou GET condicional) sejam tratadas corretamente. Este é, obviamente, o motivo do desempenho codificação de conteúdo em tempo real é uma ideia estúpida, e por isso adicionei Transfer-Encoding ao HTTP como a maneira adequada de fazer a codificação em tempo real sem alterar o recurso.

Fonte: https://issues.apache.org/bugzilla/show_bug.cgi?id=39727#c31

Em outras palavras: não faça a codificação de conteúdo em tempo real , use a codificação de transferência!

Editar: isto é, a menos que você queira servir conteúdo compactado com gzip para clientes que só entendem Content-Encoding . Que, infelizmente, parece ser a maioria deles. Mas esteja ciente de que você sai dos domínios da especificação e pode encontrar problemas como o mencionado por Fielding, bem como outros, por exemplo, quando proxies de cache estão envolvidos.

Eugene Beresovsky
fonte
3
Então, se entendi direito: 1. Codificação de conteúdo refere-se à codificação do conteúdo no servidor no abstrato, ou seja, o conteúdo será consistentemente servido na codificação especificada pelo servidor. 2. A codificação de transferência refere-se à codificação que o servidor decidiu usar para entregá-la ao agente do usuário nesta instância, ou seja, nesta resposta. Só me certificando de não interpretar mal sua resposta.
dot slash hack
30
@KemHeyndels Sobre certo. Dito de outra forma: de acordo com as especificações, Transfer-Encoding é um detalhe da camada de transporte puro , ou seja, um proxy intermediário é livre para desfazer, por exemplo, compressão gzip nesse nível, enquanto Content-Encoding é uma propriedade da camada de negócios , que um proxy não seria permitida a alteração, além de outras ramificações (ETags etc). Porém, de acordo com a realidade , o TE não é normalmente usado para compressão e muitos servidores / clientes nem mesmo o suportam fora da caixa, enquanto o CE é usado mais ou menos da maneira que o TE foi planejado para ser usado : como um detalhe da camada de transporte .
Eugene Beresovsky
1
Então, somos obrigados pela realidade a ignorar o conselho de Roy T. Fielding?
dot slash hack de
11
@KemHeyndels Você é obrigado pelo idealismo a sair e primeiro adicionar suporte TE a todas as implementações de cliente / servidor HTTP de código aberto. Em seguida, consiga um emprego em todas as empresas que têm implementações HTTP de código fechado (acho que isso é apenas a Microsoft, de qualquer maneira) e adicione o recurso lá também. Depois disso, a realidade e a especificação coincidirão. ;) (E o HTTP 2.0 terá sido lançado, fazendo com que o problema desapareça de qualquer maneira)
Eugene Beresovsky
10
Indicar que você oferece suporte para Transfer-Encoding ainda não deixa claro que você oferece suporte para gzip em vez de Transfer-Encoding, de modo que não adianta nada. A indicação é feita de forma inversa : qualquer cliente que pode fazer gzip via Transfer-Encoding informará o servidor por meio de configuração TE: gzip. E então seu servidor deve seguir a rota Transfer-Encoding. Se o cliente só fala Accept-Encoding: gzip, tem que fazer do Content-Encodingjeito. Se o cliente não especificar nenhum em sua solicitação, o servidor não deve usar gzip.
Eugene Beresovsky
27

O uso correto , conforme definido no RFC 2616 e realmente implementado in the wild, é para o cliente enviar um Accept-Encodingcabeçalho de solicitação (o cliente pode especificar várias codificações). O servidor pode então, e somente então, codificar a resposta de acordo com as codificações suportadas pelo cliente (se os dados do arquivo ainda não estiverem armazenados nessa codificação), indicar no Content-Encodingcabeçalho da resposta qual codificação está sendo usada. O cliente pode então ler os dados do soquete com base no Transfer-Encoding(ou seja, chunked) e decodificá-los com base no Content-Encoding(ou seja:) gzip.

Portanto, no seu caso, o cliente enviaria um Accept-Encoding: gzipcabeçalho de solicitação e, em seguida, o servidor pode decidir compactar (se já não estiver) e enviar um Content-Encoding: gzipe, opcionalmente, um Transfer-Encoding: chunkedcabeçalho de resposta.

E sim, o Transfer-Encodingcabeçalho pode ser usado em solicitações, mas apenas para HTTP 1.1, o que requer que as implementações de cliente e servidor suportem a chunkedcodificação em ambas as direções.

ETagidentifica exclusivamente os dados de recursos no servidor, não os dados realmente sendo transmitidos. Se um determinado recurso de URL muda seu ETagvalor, significa que os dados do lado do servidor para esse recurso mudaram.

Remy Lebeau
fonte
14
a codificação de conteúdo é uma característica da entidade identificada pelo URI de Solicitação. Em outras palavras: Diferente Content-Encodingrequer diferenteETag Este é o problema do bug mod_deflate a que me refiro em minha resposta. Me faz pensar por que esse detalhe no nível do aplicativo está no padrão HTTP em primeiro lugar. Transfer-EncodingNo entanto, ao usar uma configuração de nível de transporte, não há necessidade de alterar o ETag. Exceto que ninguém implementou Transfer-Enc.
Eugene Beresovsky
2
A codificação de conteúdo não é para a codificação "em tempo real". A RFC 2616 diz "A codificação de transferência ... difere da codificação de conteúdo porque a codificação de transferência é uma propriedade da mensagem, não da entidade." ( Tools.ietf.org/html/rfc2616#section-14.41 ) e "A codificação de conteúdo é uma característica da entidade identificada pelo URI de Solicitação. Normalmente, o corpo da entidade é armazenado com esta codificação" ( tools.ietf.org/html/rfc2616#section-14.11 ). Então eu voto contra.
Robert
O que eu descrevi é o que é " realmente implementado em estado selvagem ", independentemente da Content-Encodingvs Transfer-Encoding. Sim, o gzip deve ser propriedade da transferência de um recurso, se feito em tempo real. Por outro lado, se o recurso for armazenado compactado no servidor, ele deve ser uma propriedade do conteúdo do recurso, se enviado no estado em que se encontra. Mas o que deveria ser e o que realmente é nem sempre são a mesma coisa.
Remy Lebeau