Расставляй правильно приоритеты и не отвлекайся на мелочи

Сжатие 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).

И еще, насчет замечаний в комментариях про сложность проблемы и необходмиость поддержки древних (или странных) клиентов. Ситуация напоминает мне баянистое высказывание: "Он был настолько скуп, что лазил по порно сайтам с отключенными картинками" :), помоему проблема несколько преувеличена и скорее должна быть проблемой клиента, чем "плясками" на сервере, тем более странный контингент незначителен.