Сжатие gzip для JavaScript и CSS
В последние время многие озаботились оптимизацией и убыстрением загрузки веб страниц, и это правильно. Аппетиты растут, но всему есть предел, уже никого, я думаю, не волнует вопрос: "Жать или не жать?", ответ однозначен - "Сжимать необходимо".
Я уже писал про оптимизацию и сжатие CSS и JavaScript, где вскольз упоминал про возможность сжатия на лету через поддержку gzip со стороны сервера и клиента. Вот про эту тему поговорим сегодня более подробнее.
Все современные браузеры, включая даже самый "любимый" IE6, могут работать с gzip содержимым. Когда Вы посылаете запрос на отображение веб страницы, браузер говорит серверу, что он может принимать сжатое содержимое. В заголовке запроса это выглядит как: Accept-Encoding: gzip,deflate. В ответ, сервер может выдавать сжатое содержимое текстовых данных, которыми являются HTML страницы (в том числе и сгенерированные динамически), CSS файлы, файлы JavaScript и т.п.
Веб сервер, а мы будем говорить про Apache, должен уметь делать gzip сжатие и определять, для какого отправляемого содержимого он будет это делать.
Вообще странно, что в Интернет полно советов по использованию gzip сжатия через какие-то "магические" действия, с применением Rewrite Engine и скриптов обработки, генерящих сжатое содержимое CSS и JavaScript, мне несовсем понятны подобные действия (за исключенем, пожалуй, каких-то ограничений хостинг провайдера) по излишней изобретательности и лишней нагрузки на сервер, когда сам Apache специально заточен под работу с gzip.
В Apache, отправкой сжатого содержимого занимается модуль mod_deflate, который может быть подключен как в Windows (LoadModule deflate_module modules/mod_deflate.so), так и, естественно, скомпилирован в Linux (--enable-deflate).
А вот определением того, что жать, а что нет, должны заниматься правила фильтрации сжимаемого содержимого по запросу клиентского браузера или его MIME типу. Более доступно, это можно описать следующим правилом: Если получаемый от клиента запрос содержит разрешение на сжатие - Accept-Encoding: gzip,deflate или отправляемое содержимое несет в себе лишь текстовую информацию, то отправляемый контент однозначно необходимо жать. До Apache версии 2.1 этим занималось семейство директив AddOutputFilter, а с версии 2.1 предпочтение отдается более гибкому модулю mod_filter. Вот его мы и рассмотрим.
Как пример, один из вариантов, когда мы хотим сжимать отправляемое (resp=) содержимое, MIME тип которого (Content-Type) содержит в себе слова text или javascript, выглядит вот так:
FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate resp=Content-Type $text/
FilterProvider gzip deflate resp=Content-Type $javascript
FilterChain gzip
Мне же по душе вариант, когда клентский браузер сам говорит (req=), что он может принимать сжатое содержимое (Accept-Encoding содержит слово gzip):
FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate req=Accept-Encoding $gzip
FilterChain gzip
Рассмотрим фильтр более подробно:
- Первая строка определяет произвольное имя фильтра (gzip) и его тип, т.е. с чем мы далее будем работать (CONTENT_SET).
- Вторая, определяет обработчика того, с чем мы работаем по заданному условию. В нашем случае обработчиком будет deflate, вызываемый в том случае, если в заголовке запроса (req=), в параметре Accept-Encoding присутствует слово gzip.
- И третьей строкой мы запускаем в действие составленный нами фильтр с именем gzip в любом из контекстов сервера.
По моему все просто и доступно (контекст директив доступен через .htaccess). А теперь результат:
Как пример: размер packed версии jQuery 1.2.3, равный 29848 байт, после обработки gzip составил меньше 15K (14833 байта, можно сделать его еще меньше, до 14652 байт, отрезав комментарии).
Как я говорил, такая схема работает на ура даже с IE6, в чем вы можете убедиться просмотрев заголовки запросов и ответов через ieHTTPHeaders
[08.04.2008] Обновлено:
Прошел месяц, пора подводить итоги. Что-ж, результат замечательный, сжатие работает на ура и выигрыш в его использовании весьма ощутим, особенно на медленных дайловых соединениях. Все это дело тестировалось на сервере с четырьмя десятками разношерстных веб ресурсов. Специально обзванивал клиентов работающих через прокси сервера и друзей увлекающихся серфингом с различными веб браузерами. В итоге, с лучшей стороны себя зарекомендовало следующее звено фильтров, его я и рекомендую:
FilterDeclare gzip CONTENT_SET
FilterProvider gzip deflate resp=Content-Type $text/
FilterProvider gzip deflate resp=Content-Type $javascript
FilterProvider gzip inflate req=Accept-Encoding !$gzip
FilterChain gzip
Как видно добавилась еще одна полезная строчка контролирующая разрешение на сжатие со стороны клиента, т.е. если клиент не может разжимать (req=Accept-Encoding !$gzip), то отдаем ему несжатый контент (inflate).
И еще, насчет замечаний в комментариях про сложность проблемы и необходмиость поддержки древних (или странных) клиентов. Ситуация напоминает мне баянистое высказывание: "Он был настолько скуп, что лазил по порно сайтам с отключенными картинками" :), помоему проблема несколько преувеличена и скорее должна быть проблемой клиента, чем "плясками" на сервере, тем более странный контингент незначителен.
боюсь разочаровать, но проблема несколько более глубокая, чем заявлено. Предложенное решение описано здесь
http://webo.in/articles/habrahabr/07-gzip-all/
Спасибо, протестирую, сделаю выводы.
Хотя странно, если браузер сам говорит, что он может: Accept-Encoding: gzip,deflate, а сам не может выполнить корректную gzip обработку, это просто «замечательный» браузер какой-то…
Обратный процесс как реализовать ?
Вытаскиваю страницу сервером для дальнейшей её обработки, а она сжата «qzip». В итоге получить корректный код — не удаётся. «Донор» — не хочет реагировать на подмену Хедера, и постоянно выдаёт данные в зжатом виде. Как получить/распаковать эти данные на своем сервере ? (Очень нужно)
(Apache + Perl)
О процессах сжатия много чего написано, а вот о том, как распаковать на Apache….
Не совсем проникся Вашей задачей, но навскидку вижу два решения:
-Либо регулировать клиентский запрос через Accept-Encoding, что-бы Apache возвращал inflate содержимое.
-Либо на принимающей стороне скрипта делать gzinflate (к сожалению не знаю как это называется в Perl)
Попробовал последний вариант на своем сайте. Все работает. YSlow не ругается на несжатые js файлы. Спасибо.
А как вообще определить, используется сжатие на сервере уже или нет?
К примеру этот сайт? — http://www.secumart.com.ua
Хоть тема и старая, но не ответить не могу. Спасибо огромное автору за столь оригинальное решение, работает на УРА на всех браузерах (IE 5.0+, Opera 7+, FF2+, Chrome, Safari). Этот способ намного удобнее и легче, чем описанный на http://webo.in/articles/habrahabr/07-gzip-all/.
2 sammerset. Проверить работу сжатия можно на сайте http://www.pipeboost.com/
Спасибо за описание ! А действительно как узнать есть ли сжатие на сервере?:
Я смотрю через связку: Firefox+Firebug, если в заголовке ответа сервера есть заветная фраза: Content-Encoding gzip
значит сервер прислал сжатое содержимое
Еще можно использовать сайт, который ранее посоветовал Dmitriy.
К примеру для моего блога: http://www.pipeboost.com/GetReport.asp?URL=http%3A%2F%2Fhandynotes.ru%2F
Если есть заветная строчка: Document Status: Compressed
— значит мы жмемся
Ну наконец то получилось!
Даа, тут без ста грамм не разберешься. Придется пока заморозить эту проблему
Благодаря автору смог включить у себя сжатие!
Век бы не знал что это такое и как сделать.
реально ускорилось благодаря сжатию !
Рекомендую всем!