Хитрый 404|Настраиваем HTTP 404 на блоге

Про несуществующие страницы на блогах написано достаточно — об иерархии шаблонов темы, как правильно сделать 404, есть и подборка неплохих 404-страниц (в которую почему-то не вошли клеви лепро-дёти несуществующие страницы). Для регистрации всех обращений к 404 можно использовать и плагин вездесущего AlexKing'а, по ходу дела настругавшего миллион разнообразных дополнений к Вордпрессу.

Да тот же Кодекс предлагает отслеживать все ошибки и возвращать не только 404, но и 403, 502 и даже экзотический 402 Payment Required.

404 страница требует 404 HTTP-заголовка

Но мне лично не нравится то, что запрошенный и не существующий URL так и останется висеть в адресной строке браузера, пока нам будут показывать соответствующие разъяснения и извинения. Плюс может возникнуть ситуация «мягкого 404», когда сервер будет посылать заголовок 200 «Все нормально», а сам говорить пользователю, что страницы нет.

Some websites report a „not found“ error by returning a standard web page with a „200 OK“ response code; this is called a soft 404. Soft 404s are problematic for automated methods of discovering whether a link is broken.
все та же вики

К счастью, хоть сам умный Wordpress сам отдает HTTP заголовок при попадании на 404 — ведь эта информация обрабатывается поисковиками. Но т.к. это делается только для ЧПУ лучше использовать прямую отдачу заголовков в шаблоне 404.php (а в случае нормального сайта или CMS — не забыть):

<?php ob_start();
	header("HTTP/1.1 404 Not Found");
	header("Status: 404 Not Found"); ?>
...содержание шаблона...
<?php ob_end_flush();
	exit; exit(); ?>

С включенной буфферизацией ввода (которая, в принципе, тоже избыточна) мы создаем нужный нам HTTP-заголовок (второй, со статусом — по привычке, для невероятного случая с невероятным PHP 3), а потом выводим буффер. Внутри же — выдаем хедер, сайдбар и тот контент, который увидит пользователь, промахнувшийся мимо странички.

Но этим не решить ситуацию с «зависшим» URL. Одновременно надо учитывать, что переход на шаблон 404.php движком осуществляется только с включенным ЧПУ и если пользователь не напрямую передает правильные переменные через $POST или $GET. Т.е. при обращении к http://iskariot.ru/?cat=1211 сработает шаблон category.php — для это в темах обычно делают проверку на существование записей, и по else выводят соответствующее сообщение. Мало того, что это порождает необходимость писать подобное во всех необходимых шаблонах (избыточность), так еще по HTTP будет отдано 200 OK.

Более лаконичный и правильный способ — убрать вообще проверку if (have_posts ()) во всех этих шаблонах и делать ее раньше всего, в случае отсутствия записей — перенаправлять уже на несуществующую страницу без передачи переменных. Для этого мы вставим в самое начало header.php этот код:

<?php
if(!have_posts()&&($_SERVER['REQUEST_URI']!='/404/')) {
	Header('Location: '.get_bloginfo('url').'/404/');
	exit;
} ?>

Соответственно, мы проверяем на наличие постов и, если их нет — отправляем пользователя по 302 редиректу на страницу вида http://iskariot.ru/404/, где его уже ждет приятная неожиданность. Вторая проверка на запрашиваемый URI делается для того, чтобы при использовании в шаблоне 404.php хедера ничего не зацикливалось. Естественно, если несуществующая страница не использует основной хедер блога, то придется эту же проверку использовать и в нем.

Наконец, отправляем в самое начало .htaccess в корневой папке строчку:

ErrorDocument 404 /404/

для того, чтобы быть полностью уверенным в том, что все, кому надо (в первую очередь, Яндекс с Гуглом) обязательно поняли бы, что это именно несуществующая страница, а не какая-нибудь другая.

Если же нам не нужен редирект и мы хотим, чтобы в строке адреса все-таки оставался неправильно введенный URL (но отсылались нормальные заголовки), в хедере вместо выше написанного используем следующий код:

<?php if(!have_posts()&&!is_404()) {
	include_once('404.php');
	exit;
} ?>

Проверить результат теперь можно с помощью просмотрщика отдаваемых HTTP-заголовков. Несмотря на двойную отдачу заголовка, все работает корректно.

Вот и все — все дырки с HTTP-заголовками и 404 страницой мы закрыли, теперь она находится в одном месте и никуда больше не денется. Остается только придумать, как обустроить ее внутренности — лучшим вариантом, на мой взгляд, будет выдать на ней ссылку на главную страницу, архивы и популярные посты. Ну и следовать прочим уже много раз разъясненным правилам.

{7 комментариев} Подписка на комментарии

В смысле? Нахера при 404 ошибке рерайтить на какую-то другую страницу? Адрес должен оставаться в строке адреса!!1111

Возможно, ты и прав. Делают и так, и так — разницы особой нет.

Твой вариант с оставлением адреса — он как бе удобен, т.к. можно будет «поправить» адрес. Трабл только в том, что в блогах вручную редко набирают страницы — если только дело не касается поддоменов или чего-нибудь важного. Если ты пришел по ссылке, то тем более не станешь что-то исправлять — просто не знаешь, что именно :).

Во многих проектах это также бесмыссленно. Поисковик, конечно, поймет все и сольет страницы вместе, но иногда нужно иметь одну единственную 404. А для удобства можно и выводить запрошенный урл текстом или даже ссылкой в ноиндексе.

Впрочем, главное — чтобы правильно отдавались заголовки. С включенным ЧПУ проблема будет всего лишь одна — когда запрашивают страницу с параметрами, чтобы не выдавалось 200. Вместо проверки на УРИ — делаем проверку на ис_404, и вместо хедера — обычный инклюд. Хотя сам понимаешь, на блогах сама 404 — редкость, не то что обращение вида ?cat=..., когда включен ЧПУ.

А уж оставлять или не оставлять строку адрес — это решение каждого (типа, да, на вкус, на цвет, на взгляд). Зависит от конкретики.

Объясните мне кто нибудь, как 404 http заголовок подделать под 200/ok ? в том же самом вордпресс

@Харьковский Веб-мастер: отдать в начале страницы 404.php хедер 200 с помощью php (). Только ума не приложу, зачем это надо.

честно говоря страница 404 нужна, и если есть возможность сделать ее забавной — здорово. Придумывайте, креативьте, удачи

А что делать с урлами вида iskariot.ru/development/?jkhgkjhgl, iskariot.ru/?jkhgkjhgl и т.п ? Тоже отдает заголовок 200 ок, что у тебя на блоге, что у меня...

А ничего. Это вполне корректные урлы — просто get-запрос с переменной jkhgkjql, равной null'у. Поисковики и люди рассматривают такие страницы как одну ;)

А здесь можно оставить свое мнение ↓ Подписка на комментарии
какие-то из следующих трех полей можно оставить пустыми


нет тегам!!! **эмоция**, __ирония__, >цитата, {[код]}