Гид по технологиям

HTTP-заголовки для кэширования в Squid

7 min read Кэширование Обновлено 22 Nov 2025
HTTP-заголовки для кэширования в Squid
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 минут

  1. Найти публичные ресурсы, которые можно кэшировать.
  2. В коде выставить:
header("Cache-Control: must-revalidate, max-age=0, s-maxage=600");
header("Vary: Accept-Encoding");
  1. Убедиться, что Set-Cookie не отправляется для этих ресурсов.
  2. Если есть логин/сессии — поставить куку LOGGED_IN при входе.
  3. В squid.conf добавить ACL для куки и запретить кэширование для неё (см. раздел выше).
  4. Перезапустить Squid и проверить заголовки/возвраты (HIT/MISS).

Критерии приёмки

  • Для анонимного пользователя страница возвращает X-Cache: HIT после первого запроса и возраст Age > 0.
  • Для залогиненного пользователя соответствующая страница всегда возвращает MISS и не кэшируется прокси.
  • Клиент без поддержки gzip получает незжатую версию (проверить Accept-Encoding).
  • Никакие критические страницы не кэшируются ошибочно (например, страницы с персональными данными).

Тест-кейсы (приёмочные)

  1. Анонимный пользователь запрашивает /page — первый запрос MISS, второй запрос HIT, Age > 0.
  2. Залогиненный пользователь запрашивает /dashboard — всегда MISS, сервер устанавливает LOGGED_IN.
  3. Запрос с Accept-Encoding: gzip — получить Content-Encoding: gzip; запрос без gzip — получить незжатую версию.
  4. Убедиться, что страница без 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.

Ссылки


Краткий итог

Правильная комбинация Cache-Control (с акцентом на s-maxage для прокси) и Vary: Accept-Encoding — основной инструмент для управления кэшированием в Squid. Исключайте персонализованные ответы через Set-Cookie/ACL. Тестируйте поведение с реальными заголовками (curl/LiveHTTPHeaders) и определяйте критерии приёмки для ваших сценариев.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Загрузочный USB‑диск с Windows — инструкция
Инструкции

Загрузочный USB‑диск с Windows — инструкция

Как отключить безопасный режим в Tumblr
Инструкции

Как отключить безопасный режим в Tumblr

Копирование пользовательских представлений Outlook
Outlook

Копирование пользовательских представлений Outlook

Очистка Docker-образов и освобождение места
DevOps

Очистка Docker-образов и освобождение места

Обновить Cube WP10 до Anniversary Update
Мобильные устройства

Обновить Cube WP10 до Anniversary Update

Как проверить, запущен ли Docker daemon
DevOps

Как проверить, запущен ли Docker daemon