Pull to refresh

Заголовок Last-Modified, Symfony и ускорение поисковой индексации

Symfony *
Многие разработчики при создании сайтов забывают про очень полезный заголовок Last-Modified, благодаря которому можно оптимизировать загрузку web-страниц и облегчить работу поисковым роботам. Далее я постараюсь восполнить этот досадный пробел.


Для чего нужен заголовок Last-Modified?


Функцией заголовка как можно догадаться из названия служит информирование клиента о дате последней модификации web-документа. Исходя из спецификации rfc 2616, клиент может «спросить» у веб сервера не изменилась ли страница с определенного числа, послав серверу заголовок «If-Modified-Since». Если страница не изменилась сервер возвращает только заголовок «304 Not Modified», в противном случае – сервер возвращает заголовок «200 OK» и тело страницы. Как видно, выгода на лицо как для сервера, так и для клиента: браузер не будет грузить страницу снова и снова, а веб сервер будет отдавать меньше данных.



Какие сайты индексируются лучше? Динамические или статичные?


Пару лет назад среди SEO-шников водились споры по поводу того, какие сайты индексируются лучше? Динамические, написанные например на php, или статичные, без использования языков программирования. Зная о заголовке Last-Modified, можно ответить на этот вопрос. Все дело в том, что веб сервер сам обрабатывает заголовок «If-Modified-Since» если файл статичный. В случае динамической генерации страницы вся ответственность за ответ ложится на язык программирования и разработчика. А так как разработчик за частую не интересуется этим вопросом, то заголовки не отдаются вовсе.

Как заголовок Last-Modified ускоряет поисковую индексацию?


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

Представьте. Есть сайт с 10 тысячами страниц. Сайт написан на php. Не отдается корректно заголок Last-Modified. Поисковой робот не может получить информацию о том, обновилась ли страница сайта с момента последнего индексирования. Что он делает? Индексирует все страницы!!! А не только те, которые изменились.
Конечно! На многих сайтах используют Sitemap. Но Sitemap это рекомендация, помощь поисковому оптимизатору. Заменой заголовка Last-Modified он быть не может!

Настройка и обработка заголовока Last-Modified в php


Для того чтобы веб-сервер передавал php-backend'у заголовок If-Modified-Since необходимо ему от этом сообщить!

Для связки nginx + php так,
location ~ \.php$
{
  …
  if_modified_since off;
      
  fastcgi_pass  fcgi;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME /<путь > /web$fastcgi_script_name;
  …
  fastcgi_pass_header Last-Modified;
  include fastcgi_params;
}


* This source code was highlighted with Source Code Highlighter.


Для связки apache + php, так
# If-Modified-Since (if php is not installed as cgi then comment lines below)
RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]


* This source code was highlighted with Source Code Highlighter.

Если php работает как модуль, то ничего настраивать не надо!

Простой php-код обработки запроса If-Modified-Since,
$qtime = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])? $_SERVER['HTTP_IF_MODIFIED_SINCE']:'' ;

$modified = substr(gmdate('r', $timestamp), 0, -5).'GMT';

if ($hdr == $modified)
{
header ("HTTP/1.1 304 Not Modified ");
header ("Last-Modified: $modified");
exit();
}
header ("Last-Modified: $modified");
//render


* This source code was highlighted with Source Code Highlighter.


Как обрабатывать запрос If-Modified-Since в symfony?


В symfony уже предусмотрен механизм обработки заголовка. Все что нужно разработчику, так это передать в объект sfWebResponse заголовок. В случае его указания фрейморк все сделает сам.
$datestamp = time();
$response->setHttpHeader('Last-Modified', $response->getDate($datestamp));


* This source code was highlighted with Source Code Highlighter.

Так как на странице как правило располагается разный контент, то я написал метод, который выставляет самый поздний из переданных заголовков!
static public function setLastModified($datestamp)
{
    $response = sfContext::getInstance()->getResponse();
    $request = sfContext::getInstance()->getRequest();

    if(is_array($datestamp))
    {
      rsort($datestamp, SORT_NUMERIC);
      $datestamp = $datestamp[0];
    }

    if(!$response->hasHttpHeader('Last-Modified'))
    {
      $response->setHttpHeader('Last-Modified', $response->getDate($datestamp));
    }
    else
    {
      $origLastModified = strtotime($response->getHttpHeader('Last-Modified'));
      if($origLastModified < $datestamp)
        $response->setHttpHeader('Last-Modified', $response->getDate($datestamp));
    }
}


* This source code was highlighted with Source Code Highlighter.

Его очень удобно использовать в случае, если на странице, например, располагается 3 последних видеролика, 3 последних статьи и там еще что-нибудь. Загружая каждую модель из базы данных, мы можем вызывать метод, и в итоге в ответе получив самую позднюю дату модификации.
Для интересующихся код обработки заголовка находится в классе sfCacheFilter.class.php.

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

Еще,

Проверить сайт на корректную обработку заголовка можно тут или так,

<?php
$ch = curl_init();
  
  $url = 'http://site.ru/1.php ';
  
  curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
      'If-Modified-Since: Sun, 28 Nov 2010 15:45:53 GMT'
    ));
   
  ob_start();
  curl_exec ($ch);
  curl_close ($ch);
  $data = ob_get_contents();
  ob_end_clean();
  
  
  echo nl2br($data);
?>

* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
Total votes 29: ↑27 and ↓2 +25
Views 36K
Comments 25
Comments Comments 25