Ich würde mich sehr über Hilfe beim Verständnis dieses Apache-Verhaltens freuen.
Ich kommuniziere mit PHP über eine iPhone Objective-C-App in application / json. Die Gzip-Komprimierung ist auf dem Server aktiviert und wird vom Client angefordert.
Aus meiner .htaccess:
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json
Für kleine Anfragen setzt Apache den 'Content-Length'-Header. Zum Beispiel (diese Werte werden in Objective-C aus dem Header ausgegeben):
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 ist ein Header, den ich zur Größe der unkomprimierten JSON-Zeichenfolge hinzufüge.
Wie Sie sehen, ist diese Anforderung sehr klein (217 Byte).
Hier sind die Header einer größeren Anfrage (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;
Beachten Sie, dass die Inhaltslänge nicht angegeben ist.
Meine Fragen:
- Warum sendet Apache die Content-Length für die größere Anfrage nicht?
- Bedeutet die Tatsache, dass 'Contend-Encoding = gzip' gesetzt ist, dass die gzip-Komprimierung immer noch bei der größeren Anforderung funktioniert, obwohl ich den Größenunterschied nicht überprüfen kann?
- Gibt es eine Möglichkeit, Apache dazu zu bringen, die tatsächliche Inhaltslänge für diese größeren Anforderungen anzugeben, um den Benutzern die Datennutzung genauer zu melden?
Diese App kann für Datentarife verwendet werden, die teuer sind. Daher möchte ich dem Benutzer den tatsächlichen Verbrauch melden, nicht 30-70% überhöhten Verbrauch (ein paar hundert zusätzliche KB klingen möglicherweise nicht nach viel - aber diese Tarife können zwischen 1 USD kosten und $ 10 pro MB!).
Danke im Voraus.
quelle
Klingt so, als ob Apache eine Chunk-Codierung ausführt. Dies bedeutet, dass die Daten während der Gzip-Verarbeitung gesendet werden können, anstatt auf die vollständige Gzip-Antwort zu warten. Es ist ziemlich üblich, aber ich kenne Apache nicht genug, um zu sagen, ob es deaktiviert werden kann.
quelle
OK, ich habe es geschafft, das zu lösen. Wie Martin F richtig hervorhebt, teilt Apache die Antwort so auf, dass die Inhaltsgröße nicht bekannt ist. Für viele Menschen ist dies wünschenswert (Seite wird schneller geladen). Dies hat den Nachteil, dass der Download-Fortschritt nicht gemeldet werden kann.
Für diejenigen wie mich, die wirklich über den Download-Fortschritt berichten möchten, gibt es wenig zu tun, wenn Sie die automatische gzip-Unterstützung von Apache oder PHP verwenden. Die Lösung besteht darin, es manuell zu tun. Es ist einfacher als es klingt:
Wenn Sie ganze Dateien senden, ist dies ein großartiges Beispiel in PHP, um einen einzelnen Block (mit der Inhaltslänge) zu erzwingen: http://www.php.net/manual/en/function.ob-start.php # 94741
Wenn Sie generierte Daten senden, verwenden Sie gzencode, um Ihre Daten zu verschlüsseln, wie im obigen Beispiel. Voraussetzung ist, dass alle Ihre Ausgabedaten in einer Variablen gespeichert sind (Sie können ob_start verwenden, um dies zu unterstützen, wenn Sie puffern müssen, und dann den Inhalt des Puffers abrufen).
Und voila!
Ein weiterer großer Vorteil ist, dass Sie die Komprimierungsstufe einstellen können. Dies ist ideal für meine mobile Anwendung, da ich die höchste Komprimierungsstufe einstellen kann (sodass meine Benutzer weniger für Daten bezahlen!) - während der Server wahrscheinlich nur eine mittlere Komprimierungsstufe verwendet, um einen besseren Kompromiss zwischen CPU und Größe zu erzielen. Komprimierungsstufen können Sie meines Erachtens nur ändern, wenn Sie die Datei httpd.conf bearbeiten können (was bei Shared Hosting nicht möglich ist).
Daher habe ich meine DEFLATE .htaccess-Direktive für alles außer meinen application / json-Antworten beibehalten, die ich jetzt auf die oben beschriebene Weise codiere.
Nochmals vielen Dank, Martin F., du hast mir den Funken gegeben, den ich brauchte, um das zu lösen :)
quelle
strlen($replyBody)
anstelle von verwendenmb_strlen($replyBody, 'latin1')
. Die Inhaltslänge ist nur die Anzahl der Bytes (nicht der Zeichen), die Sie mit strlen () erhalten. Die Verwendung von mb_strlen () mit 'latin1' funktioniert, da latin1-Zeichen immer 8 Bit lang sind. Es kann jedoch Probleme mit Codierungen geben, die Bytes erzeugen, die keine gültigen latin1-Zeichen sind.