Dokumentacja
Zwracaj 404 dla nieistniejących stron
Zwracaj 404 dla nieistniejących stron
Gdy ktoś otwiera adres, który nie istnieje, serwer powinien odpowiedzieć statusem 404 Not Found (albo 410 Gone dla strony usuniętej celowo). Wiele witryn pokazuje stronę błędu, ale wysyła ją ze statusem 200 OK, albo przekierowuje każdy nieznany adres na stronę główną. Dla odwiedzającego wygląda to tak samo. Dla Google to miękki 404 (soft 404): strona, która twierdzi, że istnieje, ale nie ma własnej treści.
Koszt jest realny. Google marnuje czas indeksowania na puste adresy, stare linki i literówki na zawsze pozostają "poprawne", a raporty w Search Console zapełniają się ostrzeżeniami o miękkich 404, które zasłaniają prawdziwe problemy. Narzędzia do wyszukiwania uszkodzonych linków, w tym nasze, nie odróżnią brakującej strony od działającej. Lista kontrolna strony żąda adresu, który nie może istnieć w Twojej witrynie, i ostrzega, gdy odpowiedź to nie 404 ani 410.
Co to powoduje
| Co się dzieje | Typowa przyczyna |
|---|---|
| Strona błędu, status 200 | własna strona błędu serwowana jak zwykła strona; SPA lub trasa łapiąca wszystko, która rysuje "nie znaleziono" w przeglądarce; nginx try_files … /index.html |
| Przekierowanie na stronę główną | wtyczka WordPress, która wysyła wszystkie 404 na stronę główną; reguła przekierowania na serwerze, w CDN lub w kreatorze stron |
| Przekierowanie na stronę błędu, potem 200 | Apache ErrorDocument z pełnym URL; nginx error_page 404 z URL; błędy IIS w trybie przekierowania |
Podążamy za przekierowaniami tak jak przeglądarka, więc brakująca strona, która kończy się na stronie głównej z 200, liczy się jako miękki 404. Przekierowanie ze starego adresu na jego nową stronę jest w porządku; do tego służą przekierowania. Wysyłanie każdego nieznanego adresu na stronę główną już nie.
Sprawdź sam
Zamiast example.com wpisz swoją stronę. Poniższy adres nie istnieje w żadnej witrynie:
curl -s -o /dev/null -w '%{http_code} %{url_effective}\n' -L https://example.com/this-page-does-not-exist-7f3a
curl -sI https://example.com/this-page-does-not-exist-7f3a | grep -iE '^(HTTP|location):'
Pierwsze polecenie podąża za przekierowaniami i wypisuje końcowy status i adres, drugie pokazuje pierwszą odpowiedź. Naprawione oznacza 404 (lub 410) w obu, bez nagłówka Location.
Jak to naprawić
Wybierz to, do czego masz dostęp. Cel jest wszędzie ten sam: zachowaj ładną stronę błędu, ale wysyłaj ją ze statusem 404 i pod adresem, o który prosił odwiedzający.
WordPress
WordPress sam zwraca 404 dla brakującego adresu, z szablonem 404.php z motywu. Gdy tak nie jest, zmienia to coś innego:
- Wtyczka do przekierowań. Najczęstszą przyczyną są wtyczki, które "przekierowują wszystkie 404 na stronę główną". Przejrzyj Plugins → Installed Plugins i poszukaj takiej, która ma 404 lub redirect w nazwie albo opisie. We wtyczkach do przekierowań poszukaj opcji przekierowującej każdy 404 i wyłącz ją. Przekierowania dla konkretnych starych adresów zostaw.
- Motyw. Otwórz
404.phpw motywie. Jeśli wywołujewp_redirect()lubwp_safe_redirect(), motyw odsyła odwiedzających gdzie indziej. Nadpisz404.phpw motywie potomnym wersją bez przekierowania. - Bezpośrednie odnośniki. Jeśli brakujące strony pokazują stronę główną w ogóle bez przekierowania, otwórz Settings → Permalinks i kliknij Save Changes bez żadnych zmian. To zapisze od nowa reguły w
.htaccess.
Jeśli stronę 404 zaprojektowano kreatorem stron (na przykład szablonem Elementor Theme Builder), status pozostaje 404; zmienia się tylko wygląd.
Następnie wyczyść pamięć podręczną stron: niektóre wtyczki cache mogą zapisać miękki 404 jako zwykłą stronę.
nginx
Zajrzyj do bloku server { … } witryny: /etc/nginx/sites-available/example.com na Debianie i Ubuntu, /etc/nginx/conf.d/example.com.conf na Rocky, Alma i CentOS.
Strona statyczna. Ostatni element w try_files decyduje, co się dzieje z nieznanym adresem. Ustaw =404, a własną stronę pokaż przez error_page:
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
Trzy warianty powodują miękki 404:
try_files $uri $uri/ /index.html;serwuje stronę główną dla każdego adresu, z 200. To typowa konfiguracja aplikacji jednostronicowej (SPA); co wtedy zrobić, opisuje zakładka Node.js i Next.js.error_page 404 = /index.html;ze znakiem=zastępuje 404 statusem serwowanej strony (200). Usuń=.error_page 404 https://example.com/;z pełnym URL wysyła przekierowanie. Użyj ścieżki lokalnej.
Aplikacje PHP (WordPress, Laravel) używają try_files $uri $uri/ /index.php?$args;. To jest poprawne: decyduje aplikacja i sama zwraca 404.
Sprawdź i zastosuj:
sudo nginx -t && sudo systemctl reload nginx
Apache i LiteSpeed
W .htaccess w katalogu głównym witryny (lub w wirtualnym hoście na własnym serwerze) użyj dla strony błędu ścieżki lokalnej:
ErrorDocument 404 /404.html
Z pełnym URL (ErrorDocument 404 https://example.com/404.html) Apache zamiast statusu 404 wysyła przekierowanie na tę stronę, a odwiedzający ląduje na stronie błędu, która odpowiada 200.
Dwie inne linie powodują miękki 404 na stronach statycznych i w aplikacjach jednostronicowych:
# Każdy nieznany adres dostaje index.html ze statusem 200:
FallbackResource /index.html
RewriteRule . /index.html [L]
Na stronie statycznej usuń je. W aplikacji jednostronicowej zajrzyj do zakładki Node.js i Next.js.
Na własnym serwerze sprawdź i zastosuj:
sudo apachectl configtest && sudo systemctl reload apache2
(httpd zamiast apache2 na Rocky, Alma i CentOS. Zmiany w .htaccess działają od razu.)
Node.js i Next.js
Next.js, App Router. Twój app/not-found.tsx jest wysyłany ze statusem 404, gdy żadna trasa nie pasuje. W trasach dynamicznych ([slug], [...slug]) musisz to zgłosić sam, gdy nie ma nic do pokazania; inaczej strona renderuje się pusta z 200:
import { notFound } from 'next/navigation';
export default async function Page({ params }) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) {
notFound();
}
return <Article post={post} />;
}
Next.js, Pages Router. Zwróć { notFound: true } z getStaticProps lub getServerSideProps; Next.js poda wtedy pages/404.js z 404.
Express. Dodaj handler po wszystkich trasach:
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, 'public', '404.html'));
});
Aplikacje jednostronicowe bez serwera (React, Vue lub Angular zbudowane do plików statycznych). Serwer wysyła index.html dla każdego adresu i tylko przeglądarka wie, że trasa nie istnieje, więc status to zawsze 200. Prawdziwe poprawki są po stronie serwera: renderuj lub prerenderuj strony (Next.js, Nuxt, Astro, krok prerenderingu) albo przekaż serwerowi WWW listę prawdziwych tras i zwracaj 404 dla pozostałych. Do tego czasu dodaj przynajmniej <meta name="robots" content="noindex"> do widoku "nie znaleziono", aby Google nie zatrzymywał tych adresów.
Laravel
Laravel zwraca 404, gdy żadna trasa nie pasuje, i pokazuje resources/views/errors/404.blade.php, jeśli go masz, z zachowaniem statusu. Miękki 404 bierze się z kodu, który łapie wszystko:
// Miękki 404: trasa zapasowa, która zwraca stronę ze statusem 200.
Route::fallback(fn () => view('home'));
// Poprawnie: zostaw trasę zapasową, ale odpowiadaj 404.
Route::fallback(fn () => response()->view('errors.404', [], 404));
W kontrolerach używaj findOrFail() lub abort(404), gdy rekord nie istnieje, zamiast zwracać widok z pustym stanem:
$post = Post::where('slug', $slug)->firstOrFail();
Cloudflare
Cloudflare Pages. Jeśli wdrożone pliki nie mają 404.html na najwyższym poziomie, Pages traktuje projekt jako aplikację jednostronicową i dla każdego nieznanego adresu serwuje index.html z 200. Dodaj 404.html do wyniku budowania, a Pages wyśle go ze statusem 404.
Workers ze statycznymi plikami. W konfiguracji Wrangler not_found_handling = "single-page-application" działa tak samo. Dla witryny, która nie jest aplikacją jednostronicową, użyj "404-page".
Reguły przekierowań. Jeśli nieznane adresy kończą się na stronie głównej, sprawdź w panelu domeny Rules, czy nie ma reguły przekierowania lub Page Rule z symbolem wieloznacznym, która wysyła wszystko na /. Zawęź ją do starych adresów, dla których była przeznaczona.
IIS i ASP.NET
W web.config serwuj własną stronę zamiast błędu, a nie jako przekierowanie:
<configuration>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="/404.html" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</configuration>
responseMode="Redirect" wysyła 302 na stronę błędu, która potem odpowiada 200. Starsze ustawienie ASP.NET <customErrors> domyślnie robi to samo; jeśli go używasz, ustaw redirectMode="ResponseRewrite".
Statyczny HTML
Hostingi statyczne szukają pliku 404.html i wysyłają go ze statusem 404: Netlify, GitHub Pages, Cloudflare Pages i większość innych. Umieść go w katalogu głównym witryny.
Na Netlify reguła łapiąca wszystko w _redirects lub netlify.toml zamienia każdy nieznany adres na stronę główną z 200:
/* /index.html 200
Usuń ją, chyba że witryna jest aplikacją jednostronicową. Na zwykłym hostingu współdzielonym skorzystaj z zakładki Apache i LiteSpeed.
Platformy hostowane
Shopify, Wix, Squarespace i Webflow zwracają prawdziwy 404 dla brakujących stron i pozwalają zaprojektować stronę 404. Jeśli sprawdzenie i tak nie przechodzi, poszukaj przekierowania: aplikacji Shopify przekierowującej 404, reguły z symbolem wieloznacznym wśród przekierowań 301 w Webflow albo przekierowania URL w Wix lub Squarespace, które wysyła całą ścieżkę na stronę główną.
Potwierdź poprawkę
Uruchom ponownie oba polecenia curl z sekcji Sprawdź sam, potem otwórz cel w PulseKeeper i kliknij Sprawdź teraz na zakładce Lista kontrolna. Pozycja zmieni się na OK w ciągu kilku minut, a nie dopiero przy kolejnym codziennym sprawdzeniu.