Eu realmente aprecio alguma ajuda para entender esse comportamento do Apache.
Estou me comunicando com o PHP a partir de um aplicativo iPhone Objective-C no aplicativo / json. A compactação gzip é ativada no servidor e solicitada pelo cliente.
Do meu .htaccess:
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json
Para pequenas solicitações, o Apache está configurando o cabeçalho 'Content-Length'. Por exemplo (esses valores são exibidos no Objective-C no cabeçalho):
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 185; <-------------
"Content-Type" = "application/json";
Date = "Wed, 22 Sep 2010 12:20:27 GMT";
"Keep-Alive" = "timeout=3, max=149";
Server = Apache;
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.2.13";
"X-Uncompressed-Content-Length" = 217;
X-Uncompressed-Content-Length é um cabeçalho que estou adicionando ao tamanho da string JSON descompactada.
Como você pode ver, essa solicitação é muito pequena (217 bytes).
Aqui estão os cabeçalhos de uma solicitação maior (282888 bytes):
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Type" = "application/json";
Date = "Wed, 22 Sep 2010 12:20:29 GMT";
"Keep-Alive" = "timeout=3, max=148";
Server = Apache;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.2.13";
"X-Uncompressed-Content-Length" = 282888;
Observe que o comprimento do conteúdo não é fornecido.
Minhas perguntas:
- Por que o Apache não envia o comprimento do conteúdo para a solicitação maior?
- O fato de 'Contend-Encoding = gzip' estar definido significa que a compactação gzip ainda está funcionando em uma solicitação maior, mesmo que eu não consiga verificar a diferença de tamanho?
- Existe uma maneira de conseguir que o Apache inclua o comprimento real do conteúdo para essas solicitações maiores para relatar com mais precisão o uso de dados para os usuários?
Este aplicativo pode ser usado em planos de dados caros, portanto, meu desejo de relatar o uso real ao usuário, não 30 a 70% de uso inflado (algumas centenas de KB extras podem não parecer muito - mas esses planos podem custar entre US $ 1 e US $ 10 por MB!).
Desde já, obrigado.
fonte
Parece que o Apache está codificando em partes, isso significa que ele pode enviar os dados enquanto estão sendo compactados em gzip em vez de aguardar a resposta completa ser compactada. É uma prática bastante padrão, mas não estou familiarizado o suficiente com o Apache para dizer se ele pode ser desativado.
fonte
OK, eu consegui resolver isso. Como Martin F corretamente aponta, o Apache está agrupando a resposta para que o tamanho do conteúdo não seja conhecido. Para muitas pessoas, isso é desejável (a página é carregada mais rapidamente). Isso tem o custo de não poder relatar o progresso do download.
Para quem gosta realmente de relatar o progresso do download, se você usa o Apache ou o suporte automático ao gzip do PHP, há pouco o que fazer. A solução é fazê-lo manualmente. É mais fácil do que parece:
Se você estiver enviando arquivos inteiros, este é um ótimo exemplo em PHP para forçar um único pedaço (com o Comprimento do Conteúdo): http://www.php.net/manual/en/function.ob-start.php # 94741
Se você estiver enviando dados gerados, use gzencode para codificar seus dados, como na amostra acima. Um pré-requisito é que todos os seus dados de saída sejam armazenados em uma variável (você pode usar ob_start para ajudar nisso se precisar fazer buffer e obter o conteúdo do buffer).
E pronto!
Outro grande benefício de fazer você mesmo é que você pode definir o nível de compactação. Isso é ótimo para o meu aplicativo móvel, pois eu posso definir o nível de compactação mais alto (para que meus usuários paguem menos pelos dados!) - enquanto o servidor provavelmente usa apenas um nível de compactação médio para uma melhor troca de CPU / tamanho. Os níveis de compactação são algo que acredito que você só poderá alterar se editar o httpd.conf (que na hospedagem compartilhada não posso).
Portanto, eu mantive minha diretiva DEFLATE .htaccess para tudo, exceto minhas respostas application / json, que agora codifico da maneira acima.
Mais uma vez obrigado Martin F, você me deu a faísca que eu precisava para resolver isso :)
fonte
strlen($replyBody)
vez demb_strlen($replyBody, 'latin1')
. O comprimento do conteúdo é apenas o número de bytes (não caracteres), que é o que strlen () fornece. O uso de mb_strlen () com o tipo 'latin1' funciona, pois os caracteres latin1 são sempre 8 bits, mas pode haver problemas com codificações que produzem bytes que não são caracteres latin1 válidos.