Content-Length не отправлен, когда сжатие gzip включено в Apache?

Я бы очень признателен за помощь в понимании этого поведения Apache.

Я общаюсь с PHP с приложения iPhone Objective-C в приложении /json. Сжатие Gzip включено на сервере и запрашивается клиентом.

Из моего .htaccess:

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

Для небольших запросов Apache устанавливает заголовок Content-Length. Например (эти значения выводятся в Objective-C из заголовка):

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 - это заголовок, который я добавляю к размеру несжатой строки JSON.

Как вы можете видеть, этот запрос очень мал (217 байт).

Вот заголовки большего запроса (282888 байт):

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;

Обратите внимание, что Content-Length не указывается.

Мои вопросы:

  1. Почему Apache не отправляет Content-Length для большего запроса?
  2. Установлен ли факт, что параметр «Contend-Encoding = gzip» означает, что сжатие gzip все еще работает над большим запросом, хотя я не могу проверить разницу в размерах?
  3. Есть ли способ заставить Apache включать фактический Content-Length для этих более крупных запросов, чтобы более точно сообщить об использовании данных пользователям?

Это приложение может быть использовано в дорогостоящих планах данных, поэтому мое желание сообщить о фактическом использовании пользователю, а не на 30-70% завышенном использовании (несколько сотен дополнительных КБ могут показаться не очень похожими, но эти планы могут стоимость от $ 1 до $ 10 за MB!).

Спасибо заранее.

12 голосов | спросил William Denniss 23 rdEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 23 Sep 2010 06:24:49 +0400 2010, 06:24:49

3 ответа


12

Дополнение к Martin Fjordvalds:

Apache использует закодированную кодировку, только если размер сжатого файла больше, чем DeflateBufferSize. Таким образом, увеличение этого размера буфера будет препятствовать серверу, использующему закодированное кодирование, и для более крупных файлов, в результате чего Content-Length будет отправляться даже для зашифрованных данных.

Дополнительная информация доступна здесь: http: //httpd.apache. орг /Docs /2,2 /мод /mod_deflate.html # deflatebuffersize

ответил Philippe 30 Maypm12 2012, 16:28:16
6

Похоже, что Apache выполняет кодирование с чередованием, это означает, что он может отправлять данные, поскольку он gzipped, а не ожидает, что полный ответ будет gzip. Это довольно стандартная практика, я недостаточно разбираюсь в Apache, чтобы сказать, может ли она быть отключена.

ответил Martin Fjordvald 23 rdEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 23 Sep 2010 06:35:50 +0400 2010, 06:35:50
4

Хорошо, мне удалось это решить. Как верно указывает Мартин F, Apache передает ответ, поэтому размер контента неизвестен. Для многих это желательно (страница загружается быстрее). Это связано с тем, что вы не можете сообщить о ходе загрузки.

Для таких, как я, которые действительно хотят сообщить о ходе загрузки, если вы используете автоматическую поддержку gzip в Apache или PHP, вы мало что можете сделать. Решение состоит в том, чтобы сделать это вручную. Это проще, чем кажется:

Если вы отправляете целые файлы, то это отличный пример в PHP для принудительного создания одного фрагмента (с Content-Length): http://www.php.net/manual/en/function.ob-start.php#94741

Если вы отправляете сгенерированные данные, используйте gzencode для кодирования ваших данных, как в приведенном выше примере. Предпосылкой является то, что все ваши выходные данные сохраняются в переменной (вы можете использовать ob_start, чтобы помочь это, если вам нужно буферизировать, а затем получить содержимое буфера).

        // $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;

И вуаля!

Еще одно большое преимущество заключается в том, что вы можете установить уровень сжатия. Это отлично подходит для моего мобильного приложения, так как я могу установить самый высокий уровень сжатия (так что мои пользователи платят меньше за данные!), Тогда как сервер, вероятно, использует только уровень сжатия среды для лучшего компромисса процессора /размера. Уровни сжатия - это то, что, я считаю, можно изменить только если вы можете отредактировать httpd.conf (который на общем хостинге я не могу).

Итак, я сохранил директиву DEFLATE .htaccess для всего, кроме ответов на мои приложения /json, которые я теперь кодировал выше.

Еще раз спасибо Мартину Ф, ты дал мне искру, которую мне нужно было решить:)

ответил William Denniss 23 rdEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 23 Sep 2010 08:26:19 +0400 2010, 08:26:19

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132