Главная » Статьи » Интернет |
Как разогнать свой сайт?
![]() Все просто – если например у Вас на страничке 3 CSS файла и 5 JS, браузеру при загрузке придется создавать 8 соединений и выкачивать по ним данные, а как известно, лучше несколько больших файлов чем множество мелких. Связано это с тем, что на каждую установку соединения браузер тратит время и зачастую немаленькое – до 40% времени загрузки. Стандартные методы написать некий командный файл, который пробегался бы по нужным файлам и склеивал их в один мне не нравились в принципе, ибо делать ручками вещи, которые можно сделать автоматически – в корне не верно, в данном случае хотя бы по тому, что это сказывается либо на разработке, либо на продакшене (дополнительные действия). Как говорят «никогда не переписывайте то, что можно просто вырезать и наклеить» ;) Сжатие Чем меньше объем «прокачиваемых» файлов, тем соответственно меньше время тратится на загрузку. Даже если эти файлы сжаты и мы тратим некторое время на распаковку – при современных вычислительных мощностях на клиенте эта временная затрата практически не существенна.Большинство современных браузеров поддерживают метод сжатия deflate, иногда называемый gzip по имени стандартной *nix утилиты, осуществляющей это дело. Что можно и нужно сжимать в веб? Любые текстовые запросы, как то: JS / CSS / JSON / HTML. Есть замечательный модуль для Апача mod-deflate, которым можно прямо из .htaccess указать чего сжимать и чего не сжимать, очень прост в использовании, но увы и ах! – обычно запрещенный на стандартных хостингах по причине того, что они (хостеры) опасаются за свое процессорное время. Доля разумного в этом конечно есть – этот модуль жмет все «на лету» и если не принять некоторых хитростей, каждый раз грузя страничку для нового пользователя он будет заново пережимать все CSS / JS и т.д. Если же у вас VDS и Вы – сам себе хозяин – используйте mod-deflate, ибо он хорошо отлажен и примеров применения в сети масса. А мы вернемся к обычным хостигам – есть ли выход? Даже если Вас съели, у вас всегда есть два выхода — есть выход и здесь. Причем эта задача очень хорошо ложиться на предыдущую – сейчас объясню почему. Большинство JS / CSS и других текстов – это статика, т.е. они не меняются в процессе функционирования сайта — есть смысл их объеденить, чтобы удовлетворить пункту о «склейке» + сразу же сжать. Полученные файлы мы положим в некий кэш, откуда наш Апач будет их брать и отдавать. Причем процесс мы автоматизируем через mod-rewrite. Алгоритм получится примерно такой: запрашивается некий файл со специального URL если клиент поддерживает сжатие и сжатый файл такого типа есть в нашем кэше – отдаем и завершаем обработку если же сжатие не поддерживается и есть просто файл такого типа – отдаем его и заканчиваем обработку иначе запускаем наш обработчик Условимся, что срабатывать наша модель при обращении к URLу вида «/glue/….», А файлы будут лежать в «/static/glue/…». В данном случае мы убиваем еще одного зайца — файлы будут отдаваться через PHP всего один раз — при формировании, а дальше будет все как у больших :) статику должен и будет отдавать веб-сервер. В принципе можно сделать так, чтобы папка совпадала с URL-ом, тогда чуть упростится конфиг mod-rewrite но будет не так интересно, вобщем упростить всегда можно :) Надеюсь, что в корне Вашего сайта уже живет файл .htaccess с содержанием типа такого: RewriteEngine On RewriteBase / RewriteRule ^.*$ index.php [QSA,L] Ну либо похожий. Основное условие, что если mod-rewrite не нашел чего сделать с пришедшим URL, он в конце концов вызовет какой-то скриптовый файл.В данном случае – index.php Для добавления нашего алгоритма пропишем в .htaccess следующее: Добавляем поддержку сжатых файлов .gz, а также .jz.gz и .css.gz AddEncoding gzip .gz < FilesMatch "\.js.gz$"> #для проксей Header set Cache-control: private Header append Vary User-Agent ForceType "text/javascript" Header set Content-Encoding: gzip AddCharset windows-1251 .js.gz < /FilesMatch> < FilesMatch "\.css.gz$"> #для проксей Header set Cache-control: private Header append Vary User-Agent ForceType "text/css" Header set Content-Encoding: gzip < /FilesMatch> Добавляем правило отдачи наших файлов (разыменовывание URL в физическую папку) RewriteCond %{ENV:REDIRECT_GZ} =1 RewriteCond %{REQUEST_URI} ^/glue/(.+)$ RewriteCond %{DOCUMENT_ROOT}/static/glue/%1 -f RewriteRule . - [L] Добавляем проверку на поддержку клиентом сжатия RewriteCond %{REQUEST_URI} ^/glue/(.+)$ RewriteCond %{DOCUMENT_ROOT}/static/glue/%1.gz -f RewriteCond %{HTTP:Accept-Encoding} ^.*?gzip.*$ [NC] RewriteCond %{HTTP_USER_AGENT} !^konqueror [NC] RewriteRule ^siteglue/(.*)$ /static/glue/$1.gz [L,E=GZ:1] Если сжатие не поддерживается RewriteCond %{REQUEST_URI} ^/glue/(.+)$ RewriteCond %{DOCUMENT_ROOT}/static/glue/%1 -f RewriteRule . static/glue/%1 [L,E=GZ:1] Теперь возьмемся за нашу самую главную магию – автоматическое формирование этих самых файлов. Здесь еще одна есть хитрость, в данном случае скорее — еще одна условность – в файлах html мы будем писать запросы к css или js в следующтим виде:«/glue/1.css—2.css—3-4-5.css», где «-» — это замена «/», а «--» – это разделитель файлов.Кроме того в именах могут быть только английские буквы, цифры и символ «_», по мне — этого более, чем достаточно. Конечно же, это условности и Вы можете выбрать себе другие правила и другие разделители. Например можно использовать «,» или что-либо еще. Однако я выбрал «-» из-за того что это вполне нормальный и часто встречающийся символ URL и с ним врядли могут быть всякие дурацкие проблемы типа вырезания его кривыми скриптами на проксях по пути от Вас до клиента. В файле в index.php (или что там у вас запускается согласно .htaccess?) добавляем обработчик, который проверяет URL на соответствие нашему «/glue/.*» и в случе совпадения делает echo( Glue::generate( $str ) ), где $str — то, что у нас идет в URL после последнего слэша, т.е. для «/glue/a.js» это будет «a.js» Сам класс Glue вот такой class Glue { static $allowedExt = array( "js" => array( "check" => "/^js/.*?.js$/", "delimeter" => ";n", "mime" => "text/javascript”), "css" => array( "check" => "/^css/.*.css$/", "delimeter" => "n", "mime" => "text/css” ), ); static function generate( $str ) { if ( !$str ) return null; //не нашли URL $files = array(); preg_replace( "/((?:[a-z0-9_.]+-)+[a-z0-9_.]+.([a-z0-9]+))(?:--|$)/ie", "$files[]=str_replace( -, /, "1")", $str ); if ( count( $files ) == 0 ) return null; //не нашли ни одного файла в URL $srcF = "/static”; //наша папка, откуда берется статика $dstF = "/glue”; //папка, нашего кэша $content = ""; $cext = substr( strrchr( $files[0], . ), 1 ); if ( $cext === false ) return null; //не смогли определить расширение $fd = null; foreach( self::$allowedExt as $k => $v ) { if ( $k == $cext ) { $fd = $v; break; } } if ( !$fd ) return null; //не нашли среди доступных расширений $usedNames = array(); $fdC = &$fd["check"]; $fdD = &$fd["delimeter"]; foreach( $files as $name ) { $ext = substr( strrchr( $name, . ), 1 ); if ( $ext === false || in_array( $name, $usedNames ) || $ext != $cext || !preg_match( $fdC, $name ) ) return null; //не смогли найти расширения, файл ч таким именем уже есть или расширение отличается от первоначального либо имя не удовлетворяет проверке $usedNames[] = $name; $filec = file_get_contents( "{$srcF}/{$name}" ); if ( !$filec ) return null; //не смогли найти или прочитать файл $content .= $content != "" ? $fdD . $filec : $filec; } //сохранили файл file_put_contents( "{$dstF}/{$str}", $content ); //сохранили сжатый файл $gzip = gzencode( $content, 9 );; //gzdeflate( $content, 9 ); if ( $gzip ) file_put_contents( "/{$dstF}/{$str}.gz",$gzip ); //мы должны отдать по данному запросу содержимое и mime-тип header( "Content-type: " . $fd["mime"], true ); return $content; } } Опять же, здесь лишь иллюстрируется один из способов КАК это сделать — не нравится статический класс — Вы можете выбрать любой другой способ — с блэкджеком и дамами не тяжелого поведения ;) Вот в принципе все, осталось пробежаться по файлам проекта – все таки остался кусочек «ручной» работы :( — и прописать вместо кучи скриптов один, но по правилам, описанным чуть Выше. Все – при первом запросе автоматически все соберется и начнет отдаваться. Еще одно маленькое дополнение – а что делать с контентом, отдаваемым PHP?Его тоже надо сжать! Для этого в то месте где Вы отдаете файлы текстового вида, там где отдается сформированный контент – например так echo( $content ); Сделать следующее: if ( isClientSupportGzip() ) { ob_start("ob_gzhandler"); echo( $content ); ob_end_flush(); } else echo( $content ); Это будет сжимать отдаваемый динамический контент, если клиент поддерживает сжатие. Функция, его проверяющая, взята с просторов интернета и выглядит так: function isClientSupportGzip() { if ( headers_sent() || connection_aborted() ) return false; if ( stripos( getenv( "HTTP_ACCEPT_ENCODING" ), "gzip" ) === false ) return false; if ( stripos( getenv( "HTTP_USER_AGENT" ), "konqueror" ) !== false ) return false; return true; } Для девелоппинга рекомендую завести некую константу режима разработки и в случае установки ее в 1 просто не записывать файлы в кэш и не сжимать динамику – не придется при каждом изменении в каком-либо js файле лазить и очищать нашу директорию с кэшем. Вот и все – мы чуть-чуть разогнали свой сайт ) По моим наблюдениям прирост в скорости отдачи может составлять 30-40%. Если есть какие-либо корректировки, предложения или критика – милости прошу в комменты – буду очень признателен, ибо как говорится – век учись ) Быстрых Вам сайтов, максимального сжатия и радостных клиентов ;) P.S. Если вы используете какую либо библиотеку, например jquery, на всех страницах своего проекта с одним и тем же местом расположения, рекомендую все-таки вынести ее в отельный файл, то же касается единого css – т.о. она быстрее скэшируется, браузером. При склейке JS помните особенность – склеивать надо через «;», т.к. в предыдущем файле после последней строчки может не оказаться «;» При написании обработчика формирования кэша помните о хакерах – проверяйте все и вся, при неграмотном экранировании можно насклеивать и получить в качестве статики много чего интересного, на худой конец можно путем перебора насмерть засрать Вам дисковое пространство, так что даже мистер Пропер не поможет – аккуратней вобщем. Если у Вас в сайт в самой непопулярной кодировке, чтобы все было шоколадно, заменитеForceType «text/javascript» на ForceType «text/javascript; content=windows-1251»и добавьте: AddCharset windows-1251 .js и AddCharset windows-1251 .css И еще маленький совет, придерживайтесь одинаковой очередности в указании склеиваемых файлов, ибо технически «/glue/a.js—b.js» и «/glue/b.js—a.js» это одно и тоже, а на практике вы получите два файла в кэше… Источник: http://digest.subscribe.ru | |
Просмотров: 643 | | |
Всего комментариев: 0 | |