Apache'de gzip sıkıştırması etkinleştirildiğinde İçerik Uzunluğu gönderilmiyor mu?


13

Bu Apache davranışını anlamaya yardımcı olduğum için gerçekten minnettar olurum.

Ben uygulama / json bir iPhone Objective-C app PHP ile iletişim kuruyorum. Gzip sıkıştırması sunucuda etkinleştirilir ve istemci tarafından istenir.

.Htaccess'imden:

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json

Küçük istekler için Apache 'İçerik Uzunluğu' başlığını ayarlıyor. Örneğin (bu değerler başlıktan Objective-C biçiminde çıkarılır):

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 , sıkıştırılmamış JSON dizesinin boyutuna ayarladığım bir başlık.

Gördüğünüz gibi, bu istek çok küçük (217 bayt).

Daha büyük bir isteğin başlıkları (282888 bayt):

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;

İçerik Uzunluğunun verilmediğine dikkat edin.

Sorularım:

  1. Apache neden daha büyük istek için İçerik Uzunluğunu göndermiyor?
  2. 'Contend-Encoding = gzip' ayarlanmış olması, boyut farkını doğrulayamama rağmen gzip sıkıştırmasının daha büyük istek üzerinde çalıştığı anlamına mı geliyor?
  3. Apache'nin veri kullanımını kullanıcılara daha doğru bir şekilde bildirmek için bu daha büyük istekler için gerçek İçerik Uzunluğunu dahil etmesinin bir yolu var mı?

Bu uygulama pahalı veri planlarında kullanılabilir, bu yüzden gerçek kullanımı kullanıcıya bildirmek arzum,% 30-70 şişirilmiş kullanım değil (birkaç yüz ekstra KB çok fazla gelmeyebilir - ancak bu planlar 1 $ arasında olabilir ve MB başına 10 $!).

Şimdiden teşekkürler.

Yanıtlar:


14

Martin Fjordvalds'ın yanıtı:

Apache, yalnızca sıkıştırılmış dosya boyutu DeflateBufferSize değerinden büyükse yığınlanmış kodlama kullanır. Bu nedenle bu arabellek boyutunun artırılması, sunucunun daha büyük dosyalar için de yığınlanmış kodlama kullanmasını engelleyerek Sıkıştırılmış veriler için bile İçerik Uzunluğunun gönderilmesine neden olur.

Daha fazla bilgi burada bulunabilir: http://httpd.apache.org/docs/2.2/mod/mod_deflate.html#deflatebuffersize


Güzel. Bu muhtemelen bu sorunu çözmenin en hızlı yoludur. Herhangi bir kişinin daha yüksek düzeyde kişiselleştirmeye ihtiyacı varsa (örneğin, başkalarını değil, bazı istekleri yığınlayın), manuel çözüm için answer serverfault.com/a/183856/54957 adresime bakın .
William Denniss

7

Apache yığınlı kodlama yapıyor gibi görünüyor, bu da tam yanıtın gziplenmesini beklemek yerine verileri sıkıştırılmış olarak gönderebileceği anlamına geliyor. Oldukça standart bir uygulamadır, Apache'yi devre dışı bırakılıp bırakılamayacağını söylemek için yeterince tanıdık değilim.


Bilgi için teşekkürler, beni doğru yöne doğrulttun ve ben çözdüm.
William Denniss

Kabul edilmiş. Bu soruyu okuyan herkes için - lütfen ayrıntılı bir çözüm için cevabımı okuyun. Temel olarak, yanıtı elle tamponlayarak ve sıkıştırarak parçalamayı (ve dolayısıyla sıfır içerik uzunluğunu) önleyebilirsiniz.
William Denniss

Kabul edilen cevabın orijinal sorunun cevabı değil, onu almanıza yardımcı olan bir şey olması biraz kafa karıştırıcı. Belki de işleri biraz daha açık hale getirmek için aşağıda gönderdiğin cevabı kabul etmelisin.
redbmk

@redbmk fair point, sadece nankör görünmek istemedim. Philippe aslında bunun için mükemmel basit bir düzeltmeye sahip, bu yüzden onun benimkini kabul ettim.
William Denniss

5

Tamam, bunu çözmeyi başardım. Martin F'nin doğru bir şekilde işaret ettiği gibi, Apache yanıtı tıklatıp içerik boyutu bilinmiyor. Birçok kişi için bu istenir (sayfa daha hızlı yüklenir). Bu, indirme işleminin ilerleme durumunu bildirememe maliyetiyle gelir.

Benim gibi indirme ilerlemesini gerçekten rapor etmek isteyenler için, Apache veya PHP'nin otomatik gzip desteğini kullanırsanız, yapabileceğiniz çok az şey var. Çözüm elle yapmaktır. Göründüğünden daha kolay:

Tüm dosyaları gönderiyorsanız, bu PHP'de tek bir yığın (İçerik Uzunluğu ile) zorlamak için harika bir örnektir: http://www.php.net/manual/en/function.ob-start.php # 94741

Oluşturulan verileri gönderiyorsanız, yukarıdaki örnekte olduğu gibi verilerinizi kodlamak için gzencode kullanın. Bir önkoşul, tüm çıktı verilerinizin bir değişkente depolanmasıdır (tamponlamanız ve daha sonra tampon içeriğini almanız gerekiyorsa bu konuda yardımcı olmak için ob_start komutunu kullanabilirsiniz).

        // $replyBody is the entire contents of your reply

        header("Content-Type: application/json");  // or whatever yours is

        // checks if gzip is supported by client
        $pack = true;
        if(empty($_SERVER["HTTP_ACCEPT_ENCODING"]) || strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') === false)
        {
            $pack = false;
        }

        // if supported, gzips data
        if($pack) {
            header("Content-Encoding: gzip");
            $replyBody = gzencode($replyBody, 9, FORCE_GZIP);
        }

        // compressed or not, sets the Content-Length           
        header("Content-Length: " . mb_strlen($replyBody, 'latin1'));

        // outputs reply & exits
        echo $replyBody;
        exit;

Ve işte!

Bunu kendiniz yapmanın bir başka büyük yararı da sıkıştırma seviyesini ayarlayabilmenizdir. En yüksek sıkıştırma seviyesine ayarlayabildiğim için mobil uygulamam için harika bir şey (bu yüzden kullanıcılarım veri için daha az ödeme yapıyor!) Sıkıştırma düzeyleri, yalnızca httpd.conf'u (paylaşımlı barındırmada yapamam) düzenleyebilirseniz değiştirebileceğinize inanıyorum.

Bu yüzden her şey için DEFLATE .htaccess yönergesini sakladım, ancak uygulama / json şu anda yukarıdaki şekilde kodladığım cevapları.

Tekrar teşekkürler Martin F, bunu çözmek için ihtiyacım olan kıvılcımı bana verdin :)


1
Bu arada, JSON verileriyle (yoğun şekilde tekrarlanan tuşlarla) tasarruf büyüktür , bir durumda% 77 azalma. Bu bir var büyük bir anlaşma ... MB başına 1 $
William Denniss

1
Muhtemelen sadece strlen($replyBody)yerine kullanmalısınız mb_strlen($replyBody, 'latin1'). İçerik uzunluğu sadece strlen () 'in verdiği bayt sayısıdır (karakter değil). Latin1 karakterleri her zaman 8 bit olduğundan, mb_strlen () yöntemini 'latin1' türüyle kullanmak çalışır, ancak geçerli latin1 karakterleri olmayan bayt üreten kodlamalarla ilgili sorunları olabilir.
orrd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.