Optymalizacja wydajności Drupala: kompresuj strony, pliki css i javascript za pomocą gzip

  1. Rozwiązywanie problemów z kompresją JS i CSS za pomocą GZIP
  2. Zmiany w .htaccess
  3. Zmiany w index.php
  4. Co osiągnąłem?
Wersja do druku

Ostatnio pojawiło się pytanie o optymalizację pobierania jednej z moich witryn. Oprócz standardowych działań mających na celu zwiększenie wydajności w Drupalu: minimalizowanie kodu CSS i JavaScript, dokonywanie niezbędnych ustawień na stronie „Wydajność”, postanowiłem zmniejszyć rozmiar plików i stron witryny podanych przeglądarce, kompresując je.

Po odwiedzeniu wielu stron i przeczytaniu kilku artykułów i komentarzy odkryłem, że kompresję można wykonać na dwa sposoby: używając narzędzi serwera Apache lub narzędzi PHP. Po przejrzeniu ustawień serwera na optymalizowanej stronie okazało się, że moduły mod_gzip i mod_deflate nie są zainstalowane na serwerze, co oznacza, że ​​pierwsza metoda z Apache nie jest konieczna.

Musiałem wrócić do Google i poszukać odpowiedzi na pytanie dotyczące kompresji za pomocą PHP. Wszystkie powyższe przykłady kompresji nie były odpowiednie dla Drupala lub po prostu straszne w implementacji. W końcu powstały rozwiązania oparte na jednej z metod.

Rozwiązywanie problemów z kompresją JS i CSS za pomocą GZIP

Aby włączyć kompresję plików JS i CSS w Drupalu, musisz zmienić dwa pliki: .htaccess i index.php.

Zmiany w .htaccess

W .htaccess musisz zmienić standard przekierowania Drupala na skrypt index.php. Zamiast zwykłych dwóch linii:

RewriteCond% {REQUEST_FILENAME}! -D RewriteCond% {REQUEST_FILENAME}! -F RewriteCond% {REQUEST_URI}! = / Favicon.ico RewriteRule ^ (. *) $ Index.php? Q = 1 $ [L, QSA]

wstaw następujący kod:

RewriteCond% {REQUEST_FILENAME}! -F [OR] RewriteCond% {REQUEST_FILENAME} ^. * (Js | css) (. *)? $ RewriteCond% {REQUEST_FILENAME}! -D RewriteCond% {REQUEST_URI}! = / favicon.ico RewriteRule ^ (. *) $ index.php? q = 1 $ [L, QSA]

Ogólnie rzecz biorąc, cały kod przeprowadza weryfikację adresu żądanego przez przeglądarkę, a jeśli zostanie pomyślnie przekazany, przekierowuje do pliku index.php.

Teraz wyjaśnię drugi blok kodu. Pierwsza linia sprawdza, czy żądany adres jest plikiem. Jeśli adres jest istniejącym plikiem na serwerze, cały warunek staje się fałszywy i nie następuje przekierowanie do index.php.

Domyślnie kolejne warunki RewriteCond są połączone logicznym AND. W naszym przypadku musimy użyć logicznego OR, aby pliki js i css przeszły przez warunek w drugiej linii. W tym celu umieszczam flagę [OR] na końcu pierwszej linii. Ta flaga łączy logiczny LUB bieżący i następny wiersz. Trzecia linia eliminuje katalogi serwerów.

Dlaczego potrzebuję czwartej linii, jeśli mam już pierwszą linię? Byłbym wdzięczny, gdyby ktoś wyjaśnił to w komentarzu do artykułu.

Piąta linia przekierowuje do pliku index.php po spełnieniu powyższych warunków. W tym przypadku cała część adresu po przesłaniu nazwy domeny do parametru q.

Zmiany w index.php

Po przetworzeniu przez serwer dyrektyw w pliku .htaccess, kontrola jest przenoszona do pliku index.php. Będzie także kompresować pliki i strony witryny. Aby wdrożyć tę istotną procedurę, musisz dodać następujący blok kodu do pliku index.php, zanim wszystkie inne wiersze zostaną wykonane:

<? if (substr_count ($ _ SERVER ['HTTP_ACCEPT_ENCODING'], 'gzip')) // sprawdź, czy przeglądarka obsługuje gzip lub x-gzip {if (! is_file ($ _ GET ["q"])) kompresja // jest zaznaczona Czy adres wygląda jak plik {ob_start ("ob_gzhandler"); // uruchamia przetwarzanie gzip w celu skompresowania kodu html nagłówka stron witryny („Content-Type: text / html; charset: UTF-8”); header („Cache-Control: must-revalidate”); nagłówek („Wygasa:”. gmdate („D, d MYH: i: s”, czas () + 60 * 60). ��GMT”); } else if (preg_match ("/^.*. (js | css) (& w +)? $ /", $ _SERVER ["QUERY_STRING"], $ ext)) // sprawdź, czy adres wygląda jak pliki js lub css {// część następnego fragmentu kodu pochodzi z funkcji drupal_page_cache_header () i jest wymagana do buforowania skompresowanych plików przez przeglądarkę. $ last_modified = gmdate ('D, d MYH: i: s', filectime ($ _ GET ["q"])). ' GMT ”; $ etag = '"'. md5 ($ last_modified). '&quot;'; $ if_modified_since = isset ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE'])? stripslashes ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE']): FALSE; $ if_none_match = isset ($ _ SERVER ['HTTP_IF_NONE_MATCH'])? stripslashes ($ _ SERVER ['HTTP_IF_NONE_MATCH']): FALSE; if ($ if_modified_since && $ if_none_match && $ if_none_match == $ etag && $ if_modified_since == $ last_modified) {nagłówek („HTTP / 1.1 304 Not Modified”); nagłówek („Wygasa: nie, 19 listopada 1978 05:00:00 GMT”); nagłówek („Etag: $ etag”); } else {ob_start ("ob_gzhandler"); $ myme = array ("css" => "text / css", "js" => "text / javascript"); header ("Content-Type: .. (($ myme [$ ext [1]])? $ myme [$ ext [1]]:" text / html ")."; charset: UTF-8 "); nagłówek („Last-Modified: $ last_modified”); header („ETag: $ etag”); nagłówek („Wygasa: nie, 19 listopada 1978 05:00:00 GMT”); header („Cache-Control: must-revalidate”); print file_get_contents ($ _ GET ["q"]); } exit; }}?>

Wstawiłem ten fragment kodu przed wierszem:

<? require_once './includes/bootstrap.inc'; ?>

Jeśli kompresja strony jest włączona na stronie „Wydajność” w ustawieniach Drupala, to samo skompresowanie stron nie ma sensu. Musisz więc zostawić tylko kod do kompresji plików JS i CSS. Jednak nadal wolę wyłączyć kompresję stron Drupala (ponieważ działa to w jakiś dziwny sposób) i kompresować je za pomocą mojego skryptu.

<? if (substr_count ($ _ SERVER ['HTTP_ACCEPT_ENCODING'], 'gzip')) // sprawdź, czy przeglądarka obsługuje gzip lub x-gzip {if (preg_match ("/^.* (js | css) (& w +)? $ / ", $ _SERVER [" QUERY_STRING "], $ ext) && is_file ($ _ GET [" q "])) // sprawdź, czy adres wygląda jak pliki js lub css {// część następnego fragmentu kodu zapożyczone z funkcji drupal_page_cache_header () i jest niezbędne do buforowania skompresowanych plików przez przeglądarkę. $ last_modified = gmdate ('D, d MYH: i: s', filectime ($ _ GET ["q"])). ' GMT ”; $ etag = '"'. md5 ($ last_modified). '&quot;'; $ if_modified_since = isset ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE'])? stripslashes ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE']): FALSE; $ if_none_match = isset ($ _ SERVER ['HTTP_IF_NONE_MATCH'])? stripslashes ($ _ SERVER ['HTTP_IF_NONE_MATCH']): FALSE; if ($ if_modified_since && $ if_none_match && $ if_none_match == $ etag && $ if_modified_since == $ last_modified) {nagłówek („HTTP / 1.1 304 Not Modified”); nagłówek („Wygasa: nie, 19 listopada 1978 05:00:00 GMT”); nagłówek („Etag: $ etag”); } else {ob_start ("ob_gzhandler"); $ myme = array ("css" => "text / css", "js" => "text / javascript"); header ("Content-Type: .. (($ myme [$ ext [1]])? $ myme [$ ext [1]]:" text / html ")."; charset: UTF-8 "); nagłówek („Last-Modified: $ last_modified”); header („ETag: $ etag”); nagłówek („Wygasa: nie, 19 listopada 1978 05:00:00 GMT”); header („Cache-Control: must-revalidate”); print file_get_contents ($ _ GET ["q"]); } exit; }}?>

Co osiągnąłem?

Dzięki tym ulepszeniom udało mi się uzyskać kompresję większości danych przesyłanych z witryny. Zastosowanie tego mechanizmu do plików multimedialnych, takich jak obrazy lub filmy, jest nie tylko bezużyteczne, ale także niebezpieczne dla wydajności serwera.

Ponadto udało mi się włączyć buforowanie danych skompresowanych przez przeglądarkę. W końcu wszystkie te działania pozwoliły kumulować pliki HTML, JS i CSS łącznie trzy razy i zmniejszyć wagę strony głównej o połowę .

Na przykład ta strona (na której znajduje się ten artykuł) została zoptymalizowana w następujący sposób:

Nieskompresowany skompresowany GZIP Zmniejszony rozmiar pliku HTML 37 KB 10 KB 370% CSS 90 KB 22 KB 400% JavaScript 465 KB 150 KB 310% Pełna strona (ze zdjęciami) 654 KB 244 KB 268%

PS Testowanie transferu danych między serwerem a przeglądarką przeprowadzono przy użyciu rozszerzeń Web Developer i Firebug dla przeglądarki Mozilla Firefox.

Php?
Js | css) (. *)?
Php?
Dlaczego potrzebuję czwartej linii, jeśli mam już pierwszą linię?
?GMT”); } else if (preg_match ("/^.*. (js | css) (& w +)?
Quot;'; $ if_modified_since = isset ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE'])?
Stripslashes ($ _ SERVER ['HTTP_IF_MODIFIED_SINCE']): FALSE; $ if_none_match = isset ($ _ SERVER ['HTTP_IF_NONE_MATCH'])?
Inc'; ?