Быстрая CMS
Обратная связь Карта сайта
Главная Создание сайтов Практика Строим CMS Наивное О проекте Блог

Передача HTTP-заголовка

Продолжим рассказ о том, как движок сайта должен отдавать HTTP-заголовок. Нельзя забывать, что заголовок должен выдаваться перед «телом» документа. Если уже начата передача HTML-кода, заголовок отправлять поздно, в ответ на такую попытку запоздалой передачи PHP завершит выполнение скрипта по ошибке. Именно поэтому так важен порядок формирования страницы.

В самом деле, велик соблазн все упростить: взять шаблон HTML-страницы, сделать вставки PHP-кода, которые будут в нужных местах обращаться к базе данных (или файловому хранилищу – кто чем богат) и вытаскивать на страницу нужные тексты и код. Но в этом случае вам уже никак не удастся отреагировать на запрос страницы, для которой в вашей базе нет данных. Например, при переходе по битой ссылке или намеренном вводе некорректных параметров URL такой движок уже не сможет отдать заголовок со статусом 404 – передача страницы уже началась, и только потом обнаружилось, что такой страницы нет.

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

Теперь о том, что именно должен передавать движок. В предыдущей статье уже было описание «диалога» между сервером и юзер-агентом (или роботом), из него уже понятно, какие сопроводительные данные необходимы. Но здесь мы остановимся именно на диалоге с роботом. Что нужно ему для корректного индексирования вашей страницы?

Прежде всего, нормальный статус «200 OK» – это означает, что запрошенная страница найдена и отправляется. Но именно этот статус-код заголовка наш скрипт формировать не должен. Уж если скрипт откликается на запрос, значит, он нашелся и этот код сервер отправит без нашей помощи. Мы можем его только переписать.

Следующее, что обязательно должно присутствовать – это медиатип документа и кодировка. При отправке страницы сайта это тип text/html, а кодировка – та, в которой выполнена наша страница. Вот здесь причина множества неудач с индексированием динамических страниц: когда скрипт не передает заголовок с медиатипом, при проходе через прокси-сервер хостера (обычно nginx) может быть выдан медиатип php-скрипта – application/x-httpd-php. И неминуемо начинаются проблемы с Яндексом, который запрашивает явно указанные типы документов, но серверных скриптов среди них, конечно же, нет. Поэтому прокси-сервер, сличив список запрошенных типов, выдаст ему документ в сопровождении кода статуса «406 Not Acceptable» (неприемлемый тип). Поскольку все коды из диапазона 400–499 являются кодами ошибки, робот вашу страницу не возьмет.

Еще нужно учесть, что в шапку html-страницы часто тоже добавляют медиатип и кодировку в виде мета-тега:


<meta http-equiv="Content-type" content="text/html; charset=windows-1251">

Естественно, информация в мета-теге и в заголовке должна быть одинаковой. Не путайте роботов, да и людей тоже. Этот мета-тег не обязателен, он придуман как эквивалент http-заголовка для случаев, когда управлять заголовками нет возможности (статические html-страницы). Так что по большому счету в шаблоне страницы для движка он совершенно не нужен.

Кроме медиатипа можно не полениться и передать язык документа: "Content-language: ru". Хотя поисковики и умеют определять язык документа самостоятельно, этот заголовок облегчит им задачу.

Текущую дату и время сервер передаст самостоятельно, об этом вам беспокоиться не нужно. А вот о дате и времени редакции страницы – атрибуте Last-Modified – советую позаботиться. Этот атрибут, как и ответ на запрос с атрибутом If-Modified-Since, часто вовсе отбрасывают как ненужный. А зря – к примеру, в Яндексе вы можете увидеть дату последней индексации страницы только в том случае, если в заголовках страницы передается Last-Modified. Но возиться с этим заголовком никому не хочется, поэтому в лучшем случае в нем передают текущую дату и время. Лучше, чем ничего.

С корректным откликом на If-Modified-Since вообще мало кто рискует связываться. Теоретически с ним все довольно просто: взять дату и время из запроса, сравнить с временем редакции страницы. Если время редакции раньше, чем в запросе, отдать код статуса «304 Not Modified» и страницу вообще не отсылать. А если позднее, то отправлять все как обычно. На практике же для движка с динамической генерацией страниц это далеко не простая задача.

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

В том случае, когда на странице есть какие-то автоматически формируемые анонсы (например, лента новостей), задача становится еще сложнее, поскольку здесь нам нужна дата редакции самого позднего из этих анонсов. Не забываем, что нужна дата именно последней редакции, а не создания – ведь после добавления новости вы могли ее отредактировать, не меняя даты. Вы также могли удалить одну из новостей – от этого страница, на которой выводятся анонсы, немедленно изменится. Именно поэтому большинство разработчиков предпочитает не связываться с проблемой даты редакции и попросту отдают в заголовках текущее время в Last-Modified.

Что касается описанного здесь движка, то у автора эта задача пока что входит в todo-list. Отложена до лучших времен, когда будет время немного дополнить структуру и алгоритм движка. Отложена, но не забыта: поставленная цель – Идеально Индексируемый Сайт. Ни больше, ни меньше. :-)