Alter.Org.UA  
 << Back Home EN en   Donate Donate www/www1/www2

настройка директив кеширование HTTP-сервера и сессий PHP

Вводная

Правильно работающий кеш сокращает время открытия странички, существенно уменьшает нагрузку на сервер и позволяет эффективно применять акселераторы (тот же nginx). С точки зрения клиента и оператора связи это обсуждалось в статьях об управлении трафиком и принудительном кешировании. Но для того чтобы это работало "из коробки", необходимо правильно настроить web-сервер.

Cache control

Полное описание лучше почитать в стандарте RFC-2616 section 14

также рекомендуется к прочтению инструкция от google

Understanding HTTP cache control
Server-side cache control headers
Cache-Control:
Pragma:
ETag:
Date:
Expires:
Last-Modified:
Client-side cache control headers
If-None-Match:

Если объект отсутствует в кеше клиента или промежуточном кеше запрос передается серверу и сервер отдает весь объем данных целиком. Вместе с данными в заголовках передается информация о дате создания и последнего изменения, правила кеширования и для кешируемых объектов - хеш объекта ETag и допустимое время его жизни в кеше. Если правила кеширования допускают, объект также сохраняется в кеше вместе со значением ETag.

Если объект есть в кеше и время валидации еще не подошло, данные отдаются прямо из кеша.

Если объект есть в кеше, но пришло время валидации, на срвер передается запрос с заголовком If-None-Match, содержащим один или несколько ранее переданых в ETag хешей объекта. Если хеш и соответствующие данные не поменялись, сервер должен вернуть HTTP/1.1 304 Not Modified.

Store rules

Static public - статический общедоступный объект, изменения не предвидятся. Как правило это картинки оформления, библиотечные java-скрипты и т.п.

Cache-Control: public, store, cache, no-validate
Etag: <hash>

Static private - объект, видимость или содержимое которого зависит от авторизации

Cache-Control: private, store, cache, no-validate
Etag: <hash>

Regular object - периодически меняющийся объект, допустимо считать, что не чаще чем раз в time to live секунд и логика приложения допускает временное использование устаревших данных.

Cache-Control: public/private, store, cache, max-age=<time to live<, must-revalidate
Etag: <hash>

Dynamic object - часто меняющийся объект или же логика приложения требует всегда самые свежие данные

Cache-Control: private, max-age=0, must-revalidate
Etag: <hash>
Last-Modified: <some date>

Non-cacheable object - постоянно меняющийся объект, можно cчитать, что содержимое всегда разное

Cache-Control: private, no-store, no-cache, max-age=0, must-revalidate
Pragma: no-cache
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Last-Modified: <now>
  • Cache-Control: public - можно кешировать как на стороне клиента, так и на промежуточных (прокси) серверах
  • Cache-Control: private - можно кешировать только на стороне клиента, на промежуточных (прокси) серверах кеширование запрещено, т.к. данные зависят от механизма авторизации.
  • Cache-Control: cache - можно использовать кешированую копию
  • Cache-Control: no-cache - запретить кеширование. Рекомендуется использовать совместно с no-store, т.к. иначе браузер может держать объект в истории и использовать его.
  • Cache-Control: store - можно хранить копию на диске
  • Cache-Control: no-store - нельзя хранить копию на диске или другом постоянном хранилище из соображений безопасности. Только в памяти.
  • Cache-Control: max-age - время жизни в кеше до обязательной валидации, может игнорироваться настройками кеша.
  • Cache-Control: must-revalidate - обязательно проводить валидацию, не должно игнорироваться
Validation

Объект, хранящийся в кеше подлежит валидации на сервере в любом из перечисленных случаев

  • Cache-Control: no-cache (+ no-store)
  • Expires: <date in the past>
  • Cache-Control: max-age=<time to live< expired
  • Cache-Control: max-age=0
  • Cache-Control: must-revalidate

Web server settings

Каждый web-сервер имеет свои настройки по умолчанию для cache-control, причем в разных версиях они могут быть различными. Поэтому, если хочется предсказуемого поведения, нужно все пропысывать в явном виде.

Note: некоторые модули, в т.ч. php session (см. ниже), а также фреймворки и библиотеки могут иметь свои default'ные схемы управления кеширования. Обязательно проверяйте на этот счет документацию. Иначе может оказаться, что кеширование в действительности не работает без видимой причины.

Apache settings

Note: php session по умолчанию отменяет эти настройки!


httpd.conf, apache.conf
# 5 minutes
ExpiresDefault A300

# 1 YEAR
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav)$">
ExpiresDefault A29030400
</FilesMatch>

# 1 WEEK
<FilesMatch "\.(jpg|jpeg|png|gif|swf)$">
ExpiresDefault A604800
</FilesMatch>

# 3 HOUR
<FilesMatch "\.(txt|xml|js|css)$">
ExpiresDefault A10800"
</FilesMatch>

<FilesMatch "\.(ico|gif|jpg|png|pdf|mp3|wav)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 month"
  Header append Cache-Control "public, store, cache, no-validate"
  Header append Pragma "cache"
</FilesMatch>

<FilesMatch "\.(css|js)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 week"
  Header append Cache-Control "public, store, cache, no-validate"
  Header append Pragma "cache"
</FilesMatch>

# 1 YEAR
<Directory "/var/www/date/libs">
  <FilesMatch "\.(js|css)$">
  ExpiresDefault A29030400
  Header set Cache-Control "max-age=290304000, public, store, cache, no-validate"
  </FilesMatch>
</Directory>

PHP settings

В PHP модуль session по умолчанию полностью отключает кеширование. Необходимо поменять настройки и заняться управлением кешем самостоятельно.


php.ini
session.cache_limiter =

Либо нужно использовать session_cache_limiter()


В скрипте обработка кешируемых страниц выглядит следующим образом

if(function_exists("getallheaders")) {
  $headers = getallheaders();
}

$hash = get_page_hash();

if(isset($headers) && isset($headers["If-None-Match"])) {
  if(preg_match("/".$hash."/", $headers["If-None-Match"])) {
    header("HTTP/1.1 304 Not Modified");
    exit;
  }
}

header("ETag: \"{$hash}\"");
header("Cache-Control: public, store, cache, max-age=$timeout");
header("Expires: ".gmdate ("D, d M Y H:i:s", time()+$timeout)) ;
PHP cache control example 1
require_once('cache-ctl.php');

// Обработка запроса, определяем тип кеширования
// (CACHE_STATIC, CACHE_DYNAMIC, CACHE_NORMAL, CACHE_PRIVATE, CACHE_NEVER).
// Например, для POST это может быть CACHE_NEVER, а для GET - CACHE_PRIVATE или
// CACHE_NORMAL в зависимости от запроса.
// Вычисляем хэш ответа. Это может быть md5 от тела ответа, даты модификации или чего либо другого,
// однозначно идентифицирующее версию изменяющегося объекта.

cache_ctl_if_match($hash); // return 304 Not modified if necessary
cache_ctl($level, $timeout, hash); // set cache control headers

// do request output

PHP cache control example 2
require_once('cache-ctl.php');

// Предварительная обработка запроса, определяем тип кеширования
// и хэш для первой части ответа.

cache_ctl_preset($level, $timeout, $hash);

// Продолжаем обработку, возможно, формируем еще часть ответа
// (и строим для него отдельный хеш). Проверяем доп. условия, которые могут влиять на
// ответ и его кеширование.

cache_ctl_preset($level, $timeout, $hash);

// Теперь все факторы учтены, хэш вычислен, можно формировать заголовки.
// Перед этим проверяем, передал ли клиент хэш объекта и совпадает ли он с полученным нами.

cache_ctl_if_match(); // return 304 Not modified if necessary
cache_ctl(); // set cache control headers

// do request output


2017.01.06

См. также:




Mail to alterX@alter.org.ua (remove X)  
<< Back Автор: Alter (Александр А. Телятников) Сервер: Apache+PHP под FBSD © 2002-2017