Kompresja

OxPHP domyślnie kompresuje odpowiedzi HTTP za pomocą kodowania Brotli. Kompresja stosowana jest automatycznie do tekstowych typów zawartości, gdy tylko klient je obsługuje, dzięki czemu rozmiar transferu spada bez żadnych zmian w kodzie aplikacji.

Jak to działa

Każda odpowiedź przechodzi przez ten sam zestaw kontroli, w podanej kolejności, zanim OxPHP zdecyduje, czy ją skompresować:

  1. Kontrola Accept-Encoding. Nagłówek Accept-Encoding klienta jest analizowany pod kątem obsługi br (Brotli). Żądania bez br w tym nagłówku nigdy nie są kompresowane.
  2. Kontrola typu zawartości. Typ MIME odpowiedzi jest weryfikowany względem listy kompresowalnych typów.
  3. Kontrola istniejącego kodowania. Odpowiedzi z istniejącym nagłówkiem Content-Encoding są pomijane, aby uniknąć podwójnej kompresji.
  4. Kontrola zakresu rozmiaru. Kompresowane są tylko odpowiedzi mieszczące się między 256 bajtami a 3 MB. Mniejsze odpowiedzi przynoszą niewielką korzyść; większe są strumieniowane bez buforowania.
  5. Kompresja. Stosowane jest kodowanie Brotli. Jeśli skompresowany wynik nie jest mniejszy od oryginału, wysyłana jest odpowiedź nieskompresowana.
Note

Kompresja odbywa się po wykonaniu kodu PHP i po obsłużeniu plików statycznych. Całe skompresowane ciało odpowiedzi jest przez chwilę przechowywane w pamięci, dlatego właśnie odpowiedzi powyżej 3 MB są wykluczone.

Konfiguracja

Zmienna Wartość domyślna Opis
COMPRESSION_LEVEL 4 Poziom jakości Brotli (0–11). Wyższe wartości dają mniejszy wynik kosztem większego zużycia CPU. Ustaw na 0, aby całkowicie wyłączyć kompresję

Domyślny poziom 4 równoważy współczynnik kompresji względem zużycia CPU przy serwowaniu treści webowych. Poziomy 9–11 lepiej nadają się do kompresji offline lub w czasie budowania.

Kompresowalne typy zawartości

Kompresja stosowana jest do następujących typów MIME:

Typy tekstowe:

  • text/html
  • text/css
  • text/plain
  • text/xml
  • text/javascript

Typy application:

  • application/javascript
  • application/json
  • application/xml
  • application/xhtml+xml
  • application/rss+xml
  • application/atom+xml
  • application/manifest+json
  • application/ld+json
  • application/wasm

Inne typy:

  • image/svg+xml
  • font/ttf
  • font/otf
  • application/x-font-ttf
  • application/x-font-opentype
  • application/vnd.ms-fontobject

Bez kompresji

Odpowiedzi są wysyłane bez kompresji, gdy spełniony jest którykolwiek z poniższych warunków:

  • Klient nie deklaruje br w nagłówku Accept-Encoding
  • Odpowiedź ma już nagłówek Content-Encoding (np. treść wstępnie skompresowana)
  • Ciało odpowiedzi jest mniejsze niż 256 bajtów lub większe niż 3 MB
  • Typ zawartości nie znajduje się na liście kompresowalnych (np. image/png, image/jpeg, font/woff2, application/zip — formaty te korzystają już z wewnętrznej kompresji)
  • Odpowiedź jest strumieniowana — jej długość nie jest znana w momencie wysyłania nagłówków (skrypty PHP używające oxphp_stream_flush(), Server-Sent Events). Kompresja strumienia wymagałaby zbuforowania go w całości w pamięci, niszcząc czas do pierwszego bajtu, dlatego strumieniowane odpowiedzi zawsze przechodzą bez kompresji

Nagłówki odpowiedzi

Gdy kompresja jest stosowana, OxPHP ustawia następujące nagłówki:

Nagłówek Wartość
Content-Encoding br
Content-Length Zaktualizowany do rozmiaru skompresowanego ciała odpowiedzi
Vary Dopisywane jest Accept-Encoding, co gwarantuje, że pamięci podręczne HTTP przechowują osobne wersje dla klientów z obsługą Brotli i bez niej

Rozwiązywanie problemów

Odpowiedzi nie są kompresowane

Sprawdź, czy klient wysyła Accept-Encoding: br. Większość nowoczesnych przeglądarek to robi, ale niektóre narzędzia do testowania HTTP nie dołączają tego nagłówka domyślnie.

Sprawdź za pomocą curl:

bash
curl -H "Accept-Encoding: br" -I http://localhost/

Poszukaj Content-Encoding: br w nagłówkach odpowiedzi. Jeśli go brakuje, sprawdź, czy:

  1. COMPRESSION_LEVEL nie jest ustawiony na 0
  2. Ciało odpowiedzi ma co najmniej 256 bajtów
  3. Content-Type odpowiedzi znajduje się na liście kompresowalnych powyżej
Kompresja powiększa odpowiedzi

W przypadku bardzo małych odpowiedzi (poniżej kilkuset bajtów) narzut Brotli sporadycznie daje wynik większy od oryginału. OxPHP wykrywa to i automatycznie wysyła odpowiedź nieskompresowaną — nie jest potrzebna żadna zmiana konfiguracji.

Wysokie zużycie CPU przez kompresję

Wyższe poziomy jakości (8–11) kompresują znacznie lepiej, ale zużywają znacznie więcej CPU. Jeśli zaobserwujesz wysokie zużycie CPU przez kompresję:

Rozwiązanie: Obniż COMPRESSION_LEVEL do 4 lub 5. Poziomy te zapewniają 80–90% redukcji rozmiaru maksymalnej jakości przy ułamku kosztu CPU.

Wstępnie skompresowane zasoby są kompresowane ponownie

Jeśli Twój potok budowania generuje pliki .br i ustawia na nich nagłówek Content-Encoding: br, OxPHP automatycznie pomija ponowną kompresję. Jeśli Twoja wstępnie skompresowana treść jest kompresowana ponownie, sprawdź, czy nagłówek Content-Encoding jest obecny w oryginalnej odpowiedzi, zanim uruchomi się kompresja.

Przykład Docker

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" volumes: - ./src:/var/www/html environment: - DOCUMENT_ROOT=/var/www/html/public - ENTRY_FILE=index.php - COMPRESSION_LEVEL=6

Zobacz także