Niestandardowe strony błędów
OxPHP serwuje markowe strony błędów HTML dla odpowiedzi 4xx i 5xx. Każda strona jest odczytywana z dysku raz przy starcie i serwowana z pamięci, więc podczas obsługi żądania nie dochodzi do żadnych operacji I/O na dysku.
Jak to działa
- Wczytywanie przy starcie. Przy starcie OxPHP odczytuje katalog wskazany przez
ERROR_PAGES_DIRi wczytuje do pamięci każdy prawidłowy plik{status}.html. - Zasady nazewnictwa. Nazwa pliku musi zawierać numeryczny kod statusu HTTP z zakresu 400–599 (na przykład
404.html,503.html). Pliki o nazwach nienumerycznych, z kodami statusu spoza tego zakresu (w tym200.html) lub z rozszerzeniem innym niż.htmlsą po cichu ignorowane. - Podmiana treści. Gdy OxPHP generuje odpowiedź 4xx lub 5xx, sprawdza, czy istnieje pasująca, wcześniej wczytana strona błędu. Jeśli istnieje, OxPHP podmienia jedynie treść oraz opisujące ją nagłówki:
Content-Typejest ustawiany natext/html; charset=utf-8,Content-Lengthna rozmiar strony, a nagłówki powiązane z oryginalną treścią (Content-Encoding,ETag,Last-Modified) są usuwane, aby nie mogły błędnie opisać ani ponownie zweryfikować podmienionej zawartości (na przykład treść błędu PHP skompresowana przezob_gzhandlernie sprawi, że strona HTML pozostanie oznaczona nagłówkiemContent-Encoding: gzip). Nagłówki opisujące semantykę odpowiedzi, a nie samą treść, są zachowywane w niestandardowej stronie —Content-Rangeprzy416 Range Not Satisfiable,Retry-Afterprzy529 Site is overloadedorazAllowprzy405 Method Not Allowed. - Zachowanie awaryjne. Jeśli katalog nie istnieje lub nie może zostać odczytany przy starcie, OxPHP zapisuje ostrzeżenie w logu i kontynuuje działanie bez niestandardowych stron błędów. Odpowiedzi błędów korzystają wtedy z treści w postaci zwykłego tekstu, dopóki katalog nie zostanie naprawiony, a serwer ponownie uruchomiony.
Konfiguracja
| Zmienna | Wartość domyślna | Opis |
|---|---|---|
ERROR_PAGES_DIR |
(nieustawione) | Katalog zawierający pliki HTML z niestandardowymi stronami błędów. Pliki muszą mieć nazwę {status}.html dla kodów statusu 400–599. Gdy nieustawione, odpowiedzi błędów korzystają z treści w postaci zwykłego tekstu |
Przykładowe strony
Każda strona błędu to samodzielny plik HTML o nazwie {status}.html. Utrzymuj je ze stylami umieszczonymi bezpośrednio w kodzie (inline), bez zewnętrznych zasobów — w przeciwnym razie nieudane żądanie pomocnicze zepsułoby samą stronę błędu.
Szablon wielokrotnego użytku
Skopiuj to do każdego pliku {status}.html i zmień <title>, <h1> oraz <p>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>500 — Internal Server Error</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Something went wrong</h1>
<p>Please try again in a moment.</p>
</body>
</html>Kody statusu warte dostarczenia
OxPHP podmienia treść każdej odpowiedzi 4xx lub 5xx, która dociera do potoku odpowiedzi. Oto kody, które zwraca samodzielnie, więc dostarcz plik dla każdego z nich:
| Plik | Status | Kiedy OxPHP go zwraca |
|---|---|---|
400.html |
Bad Request | Żądanie QUERY (RFC 10008) wysłane bez nagłówka Content-Type |
404.html |
Not Found | Brak pasującego pliku lub trasy; zablokowany plik z kropką (.env, .git/); bezpośrednie żądanie .php w trybie Framework; domyślne zachowanie awaryjne PHP_DENY_PATHS |
413.html |
Payload Too Large | Treść żądania przekracza maksymalny rozmiar |
416.html |
Range Not Satisfiable | Niespełnialny nagłówek Range przy pliku statycznym (Content-Range jest zachowywany) |
500.html |
Internal Server Error | Nieprzechwycony lub krytyczny błąd PHP |
503.html |
Service Unavailable | Łagodne opróżnianie podczas zamykania |
504.html |
Gateway Timeout | Żądanie przekroczyło REQUEST_TIMEOUT_SECONDS |
529.html |
Site is overloaded | Kolejka żądań jest pełna przy QUEUE_CAPACITY (Retry-After jest zachowywany) |
Każdy inny kod 4xx lub 5xx działa tak samo — dodaj 403.html, 451.html i tak dalej dla kodów zwracanych przez Twoją aplikację PHP lub dla niestandardowego statusu PHP_DENY_FALLBACK. Jedynym wyjątkiem jest 429 z mechanizmu ograniczania liczby żądań, które jest generowane przed uruchomieniem tego handlera i zawsze korzysta ze swojej domyślnej treści (zobacz uwagę poniżej).
Gotowe przykłady
Minimalna strona 404:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>404 - Page Not Found</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Page Not Found</h1>
<p>The page you requested does not exist.</p>
</body>
</html>Strona konserwacji 503 z automatycznym odświeżaniem:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="30">
<title>503 - Service Unavailable</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Service Unavailable</h1>
<p>We are performing maintenance. This page will refresh automatically.</p>
</body>
</html>Rozwiązywanie problemów
Niestandardowe strony błędów się nie pojawiają
Sprawdź, czy ERROR_PAGES_DIR jest ustawione i czy pliki mają poprawne nazwy.
Sprawdzenie: Potwierdź aktywną ścieżkę katalogu oraz to, że OxPHP zapisał przy starcie wiersze „Loaded custom error page”:
docker logs my-app 2>&1 | grep "error page"Rozwiązanie: Upewnij się, że ścieżka katalogu jest poprawna, pliki mają nazwy {status}.html, a kontener ma prawo odczytu tego katalogu.
Ostrzeżenie przy starcie o braku katalogu stron błędów
OxPHP zapisuje ostrzeżenie w logu i kontynuuje działanie bez niestandardowych stron błędów, jeśli katalog ERROR_PAGES_DIR nie istnieje lub nie może zostać odczytany. Odpowiedzi błędów korzystają wtedy z treści w postaci zwykłego tekstu. Sprawdź, czy wolumin jest poprawnie zamontowany w Dockerze:
docker run --rm -v ./errors:/var/www/errors:ro \
-e ERROR_PAGES_DIR=/var/www/errors \
ghcr.io/oxphp/oxphp:0.10.0Odpowiedź 429 nadal pokazuje domyślną treść
Niektóre odpowiedzi generowane, zanim uruchomi się potok odpowiedzi — takie jak odrzucenia z powodu ograniczania liczby żądań — nie są przetwarzane przez handler stron błędów. Odpowiedź 429 Too Many Requests z mechanizmu ograniczania liczby żądań korzysta ze swojej domyślnej treści niezależnie od tego, czy plik 429.html jest obecny.
Przykład dla Dockera
services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "8080:8080"
volumes:
- ./src:/var/www/html:ro
- ./errors:/var/www/errors:ro
environment:
ERROR_PAGES_DIR: "/var/www/errors"
ENTRY_FILE: "index.php"Struktura katalogów:
project/
src/
public/
index.php
errors/
400.html
403.html
404.html
500.html
503.html
504.html
529.htmlDobre praktyki
- Utrzymuj strony błędów jako samodzielne, z CSS umieszczonym bezpośrednio w kodzie (inline). Nie odwołuj się do zewnętrznych arkuszy stylów ani skryptów — te żądania pomocnicze same mogą się nie powieść.
- Dodaj znacznik
<meta http-equiv="refresh" content="30">do503.html, aby użytkownicy automatycznie ponawiali próbę po zakończeniu konserwacji. - Utrzymuj strony błędów małe. Każda wczytana strona jest przechowywana w pamięci przez cały czas życia procesu serwera.
Niestandardowe strony błędów dotyczą odpowiedzi przepływających przez normalny potok żądań. Odpowiedź 429 Too Many Requests z mechanizmu ograniczania liczby żądań jest generowana przed uruchomieniem handlera stron błędów i korzysta ze swojej domyślnej treści w postaci zwykłego tekstu.
Zobacz też
- Routing — jak generowane są odpowiedzi 404 dla niedopasowanych ścieżek
- Ograniczanie liczby żądań — zachowanie ograniczania liczby żądań i odpowiedzi 429
- Dokumentacja konfiguracji — pełna dokumentacja zmiennych środowiskowych