Realmente agradecería algo de ayuda para comprender este comportamiento de Apache.
Me estoy comunicando a PHP desde una aplicación iPhone Objective-C en application / json. La compresión Gzip está habilitada en el servidor y la solicita el cliente.
Desde mi .htaccess:
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json
Para solicitudes pequeñas, Apache está configurando el encabezado 'Content-Length'. Por ejemplo (estos valores se generan en Objective-C desde el encabezado):
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 es un encabezado que estoy agregando establecido al tamaño de la cadena JSON sin comprimir.
Como puede ver, esta solicitud es muy pequeña (217 bytes).
Aquí están los encabezados de una solicitud más grande (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;
Tenga en cuenta que Content-Length no se proporciona.
Mis preguntas:
- ¿Por qué Apache no envía Content-Length para la solicitud más grande?
- ¿El hecho de que 'Contend-Encoding = gzip' esté configurado significa que la compresión gzip todavía funciona en la solicitud más grande, aunque no puedo verificar la diferencia de tamaño?
- ¿Hay alguna manera de hacer que Apache incluya la longitud de contenido real para estas solicitudes más grandes para informar con mayor precisión el uso de datos a los usuarios?
Esta aplicación se puede usar en planes de datos que son caros, de ahí mi deseo de informar el uso real al usuario, no un uso inflado del 30-70% (unos pocos cientos de KB adicionales pueden no parecer mucho, pero estos planes pueden costar entre $ 1 y $ 10 por MB!).
Gracias por adelantado.
fuente
Parece que Apache está haciendo codificación fragmentada, esto significa que puede enviar los datos a medida que se comprimen en lugar de esperar a que se responda la respuesta completa. Es una práctica bastante estándar, aunque no estoy lo suficientemente familiarizado con Apache como para decir si se puede desactivar.
fuente
OK, logré resolver esto. Como Martin F señala correctamente, Apache está fragmentando la respuesta para que no se conozca el tamaño del contenido. Para muchas personas esto es deseable (la página se carga más rápido). Esto tiene un costo de no poder informar el progreso de la descarga.
Para aquellos como yo que realmente desean informar el progreso de la descarga, si usa Apache o el soporte automático de gzip de PHP, hay poco que pueda hacer. La solución es hacerlo manualmente. Es más fácil de lo que parece:
Si está enviando archivos completos, este es un gran ejemplo en PHP para forzar un solo fragmento (con Content-Length): http://www.php.net/manual/en/function.ob-start.php # 94741
Si está enviando datos generados, use gzencode para codificar sus datos, como en el ejemplo anterior. Un requisito previo es que todos sus datos de salida se almacenen en una variable (puede usar ob_start para ayudarlo si necesita almacenar en búfer, luego obtener el contenido del búfer).
¡Y voilá!
Otro gran beneficio de hacerlo usted mismo es que puede establecer el nivel de compresión. Esto es excelente para mi aplicación móvil, ya que puedo establecer el nivel de compresión más alto (para que mis usuarios paguen menos por los datos), mientras que el servidor probablemente solo usa un nivel de compresión medio para una mejor compensación de CPU / tamaño. Los niveles de compresión son algo que creo que solo puede cambiar si puede editar httpd.conf (que en el alojamiento compartido, no puedo).
Así que he mantenido mi directiva .htaccess DEFLATE para todo menos para mi aplicación / json que ahora codifico de la manera anterior.
Gracias de nuevo Martin F, me diste la chispa que necesitaba para resolver esto :)
fuente
strlen($replyBody)
lugar demb_strlen($replyBody, 'latin1')
. La longitud del contenido es solo el número de bytes (no caracteres), que es lo que le proporciona strlen (). Usar mb_strlen () con el tipo 'latin1' funciona porque los caracteres latin1 son siempre de 8 bits, pero puede tener problemas con las codificaciones que producen bytes que no son caracteres latin1 válidos.