HTTP-заголовки для кэширования в Squid
Ключевая цель и варианты запросов
- Основная цель: настроить HTTP‑заголовки так, чтобы Squid кэшировал нужные страницы.
- Варианты формулировки запроса: кэширование Squid, Cache-Control s-maxage, Vary Accept-Encoding, исключение сессионных страниц из кэша.
Заголовки HTTP и их роль в кэшировании
Кэширование не работает «из коробки»: веб‑приложение должно отправлять корректные HTTP‑заголовки. Squid кэширует страницу только если заголовки указывают, что это допустимо.
Ниже — примеры заголовков, которые запрещают кэширование (их нужно избегать для страниц, которые вы хотите кэшировать):
- Expires с датой в прошлом: “Expires: Sun, 19 Nov 1978 05:00:00 GMT”.
- Определённые Cache-Control: “Cache-Control: no-store, no-cache, must-revalidate” или “Cache-Control: must-revalidate, max-age=0, s-maxage=0”.
- Set-Cookie: страница не кэшируется, если сервер устанавливает cookie.
Если вы хотите, чтобы Squid кэшировал страницы, измените приложение так, чтобы такие заголовки не отправлялись.
Рекомендуемый подход — использовать s-maxage для прокси (Squid) и при этом запретить кэширование у браузера, чтобы избежать двойного кэширования в браузере и прокси:
"Cache-Control: must-revalidate, max-age=0, s-maxage=600"Это указывает Squid кэшировать страницу на 600 секунд (s-maxage), а браузеру — не кэшировать (max-age=0). Учтите, что одновременная отправка противоречивых заголовков (например, Expires в прошлом или Set-Cookie) делает этот заголовок бессмысленным.
Ещё один важный заголовок:
"Vary: Accept-Encoding"Он заставляет Squid хранить две копии страницы: сжатую (gzip) и незжатую, чтобы отдавать ту версию, которую понимает клиент. Некоторые user‑agent не понимают gzip, поэтому им нужна незжатая версия.
Итог: используйте оба заголовка и не отправляйте Expires в прошлом, Set-Cookie и т.п. для кэшируемых публичных страниц:
“Cache-Control: must-revalidate, max-age=0, s-maxage=600”
“Vary: Accept-Encoding”
Примеры для PHP
Если приложение на PHP, используйте header() для отправки заголовков, например:
header("Cache-Control: must-revalidate, max-age=0, s-maxage=600");
header("Vary: Accept-Encoding");Для установки куки при входе и удаления при выходе (примеры из исходника):
setcookie('LOGGED_IN', 'Y', $_SERVER['REQUEST_TIME'] + 604800, '/');(604800 секунд = 1 неделя)
setcookie('LOGGED_IN', '', $_SERVER['REQUEST_TIME'] - 31536000, '/');(установка даты в прошлом удаляет куку)
Подробнее о заголовках и кэше: http://www.mnot.net/cache_docs/
Разный контент для разных пользователей
Частая задача: кэшировать страницы для анонимных пользователей, но не кэшировать персонализированные страницы залогиненных пользователей.
Идея: ставьте куку при входе (например, LOGGED_IN=Y) и настраивайте Squid так, чтобы он не кэшировал ответы, где кука присутствует.
Откройте конфигурацию Squid:
vi /etc/squid/squid.confи добавьте следующие строки:
| [...] acl cookie_logged_in_set rep_header Set-Cookie LOGGED_IN=Y cache deny cookie_logged_in_set acl cookie_logged_in_out rep_header Cookie LOGGED_IN=Y cache deny cookie_logged_in_out acl cookie_logged_in req_header Cookie LOGGED_IN=Y cache deny cookie_logged_in |
Затем перезапустите Squid:
/etc/init.d/squid restartПояснение: правила acl и cache deny говорят Squid не кэшировать ответы, где обнаружены соответствующие заголовки/куки.
Важно: порядок правил и точность шаблонов для Cookie имеют значение — неправильный шаблон может блокировать кэширование для всех.
Отслеживание и отладка заголовков
Чтобы понять, какие заголовки отправляет ваше приложение и кэшируется ли страница, установите расширение LiveHTTPHeaders в Firefox (или используйте curl/HTTPie). Плагин покажет HIT или MISS.
Пример HIT (Age указывает возраст кэш‑копии в секундах):
HTTP/1.0 200 OK
Date: Wed, 17 Dec 2008 09:57:03 GMT
Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch13
X-Powered-By: PHP/5.2.0-8+etch13
Cache-Control: must-revalidate, max-age=0, s-maxage=600
X-UA-Compatible: IE=7
Last-Modified: Wed, 17 Dec 2008 09:06:29 GMT
Etag: “e8b0de24351dd12ab17a196fca9571a4”
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
Age: 74
X-Cache: HIT from www.example.com
X-Cache-Lookup: HIT from www.example.com:80
Via: 1.0 www.example.com:80 (squid/2.6.STABLE5)
Connection: close
Пример MISS:
HTTP/1.0 200 OK
Date: Wed, 17 Dec 2008 09:56:47 GMT
Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch13
X-Powered-By: PHP/5.2.0-8+etch13
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-UA-Compatible: IE=7
Set-Cookie: PHPSESSID=c516a650bdba0719d216d21d345cb26a; expires=Fri, 09 Jan 2009 13:30:07 GMT; path=/
Last-Modified: Wed, 17 Dec 2008 09:56:47 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 9419
Content-Type: text/html; charset=utf-8
X-Cache: MISS from www.example.com
X-Cache-Lookup: MISS from www.example.com:80
Via: 1.0 www.example.com:80 (squid/2.6.STABLE5)
Connection: close
Когда это не работает или может подвести
- Если сессии реализованы через HTTP‑заголовки или токены в URL, Squid может случайно кэшировать персонализированный контент. Решение: поставить точные ACL для исключения таких ответов.
- Если приложение выставляет Set-Cookie в любом месте ответа, Squid не будет кэшировать его — даже если у вас настроен s-maxage. Убедитесь, что Set-Cookie отправляется только для действительно персонализированных ресурсов.
- Неправильный Vary (например, отсутствие Vary: Accept-Encoding при использовании gzip) приведёт к отдаче сжатой страницы неподходящему клиенту.
- Динамические страницы с часто меняющимся контентом могут устаревать в кэше до тех пор, пока не пройдёт s-maxage. Используйте механизмы инвалидации, если важно немедленное обновление.
Альтернативные подходы
- CDN вместо/вместе с Squid: CDN обычно предоставляет гибкие правила кэширования на уровне путей и заголовков и может быть проще в управлении для глобальных сайтов.
- Кеширование на уровне приложения: если прокси не подходит, приложение само может хранить сгенерированные фрагменты в Redis/Memcached.
- ESI (Edge Side Includes): для гибридных страниц, где часть контента кэшируется, а часть всегда динамическая.
Ментальные модели и эвристики
- Прокси = кэширующий слой верхнего уровня: доверяй прокси только если заголовки явно разрешают.
- Двойное кэширование — опасно: браузер + прокси могут держать разные версии; явно управляйте max-age и s-maxage.
- Кука на вход = флаг «персонализированная» — проще всего фильтровать по ней.
Факто-бокс: ключевые цифры и значения
- s-maxage=600 — пример: Squid кэширует 600 секунд.
- max-age=0 — браузер не кэширует.
- 604800 секунд — 1 неделя (пример для жизни куки).
- Age — заголовок, показывающий возраст кэш‑копии в секундах.
Чек-листы по ролям
Разработчик:
- Отправлять корректные Cache-Control и Vary.
- Не устанавливать Set-Cookie для публичных ресурсов.
- Тестировать с curl с разными Accept-Encoding.
Системный администратор / DevOps:
- Настроить ACL в squid.conf для исключения персонализированных страниц.
- Перезапустить Squid после изменения конфига и проверить лог.
- Мониторить X-Cache заголовки и метрики кэша.
Тестировщик:
- Проверить HIT/MISS для анонимного и залогиненного пользователя.
- Проверить отдачу gzip/не gzip в зависимости от Accept-Encoding.
Быстрый SOP: что сделать за 10 минут
- Найти публичные ресурсы, которые можно кэшировать.
- В коде выставить:
header("Cache-Control: must-revalidate, max-age=0, s-maxage=600");
header("Vary: Accept-Encoding");- Убедиться, что Set-Cookie не отправляется для этих ресурсов.
- Если есть логин/сессии — поставить куку LOGGED_IN при входе.
- В squid.conf добавить ACL для куки и запретить кэширование для неё (см. раздел выше).
- Перезапустить Squid и проверить заголовки/возвраты (HIT/MISS).
Критерии приёмки
- Для анонимного пользователя страница возвращает X-Cache: HIT после первого запроса и возраст Age > 0.
- Для залогиненного пользователя соответствующая страница всегда возвращает MISS и не кэшируется прокси.
- Клиент без поддержки gzip получает незжатую версию (проверить Accept-Encoding).
- Никакие критические страницы не кэшируются ошибочно (например, страницы с персональными данными).
Тест-кейсы (приёмочные)
- Анонимный пользователь запрашивает /page — первый запрос MISS, второй запрос HIT, Age > 0.
- Залогиненный пользователь запрашивает /dashboard — всегда MISS, сервер устанавливает LOGGED_IN.
- Запрос с Accept-Encoding: gzip — получить Content-Encoding: gzip; запрос без gzip — получить незжатую версию.
- Убедиться, что страница без Set-Cookie кэшируется даже если в коде есть s-maxage.
Шпаргалка и сниппеты
- Разрешить прокси кэшировать на 10 минут:
Cache-Control: must-revalidate, max-age=0, s-maxage=600- Разрешить кэширование в браузере и прокси на 1 час:
Cache-Control: public, max-age=3600, s-maxage=3600- Исключить ресурс из кэша полностью:
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Expires: 0Совместимость и миграция
- Разные версии Squid и CDN могут иметь отличия в обработке некоторых заголовков; тестируйте на целевой версии.
- Если вы переходите с серверного кэширования на CDN, проверьте соответствие правил по Cookie и заголовкам Vary.
Ссылки
- Squid: http://www.squid-cache.org/
- Apache: http://httpd.apache.org/
- LiveHTTPHeaders Firefox plugin: http://livehttpheaders.mozdev.org/
- Caching tutorial: http://www.mnot.net/cache_docs/
- PHP: http://www.php.net/
- Debian: http://www.debian.org/
Краткий итог
Правильная комбинация Cache-Control (с акцентом на s-maxage для прокси) и Vary: Accept-Encoding — основной инструмент для управления кэшированием в Squid. Исключайте персонализованные ответы через Set-Cookie/ACL. Тестируйте поведение с реальными заголовками (curl/LiveHTTPHeaders) и определяйте критерии приёмки для ваших сценариев.
Похожие материалы
Загрузочный USB‑диск с Windows — инструкция
Как отключить безопасный режим в Tumblr
Копирование пользовательских представлений Outlook
Очистка Docker-образов и освобождение места
Обновить Cube WP10 до Anniversary Update