- добавлена сборка Caddy с Souin, Otter и NutsDB - добавлена конфигурация dev, prod и test Docker Compose - настроено кеширование через Otter L1 и NutsDB L2 - добавлены e2e-тесты Bun для кеша, restart и purge - добавлена документация по запуску, API кеша и тестам
4.5 KiB
API кеша (Souin)
Обзор
Кеширование реализовано через Souin plugin для Caddy. Обработанные изображения кешируются с TTL = 1 год.
Souin API доступен через Caddy admin API (порт 2019). Это отдельный endpoint, не доступный извне через основной порт.
Заголовки
Cache-Status
Каждый ответ содержит заголовок Cache-Status:
Cache-Status: Souin; hit; ttl=31535999; key=GET-...; detail=DEFAULT
| Значение | Описание |
|---|---|
hit |
Ответ из кеша |
fwd=uri-miss; stored |
Первый запрос, результат закеширован |
fwd=uri-miss; detail=UNCACHEABLE-* |
Запрос не может быть закеширован |
Cache-Control
imgproxy возвращает:
Cache-Control: max-age=31536000, public
Souin использует этот заголовок для определения TTL.
Souin API
API доступно через Caddy admin API на порту 2019.
Список закешированных ключей
curl http://localhost:2019/souin-api/souin/
Ответ — JSON-массив ключей:
[
"GET-http-localhost:8888-/unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg",
"GET-http-localhost:8888-/unsafe/resize:fit:200:0:0/q:60/plain/https://example.com/photo.jpg"
]
Purge по ключу (regex)
curl -X PURGE "http://localhost:2019/souin-api/souin/.*example.com/photo.jpg"
regex — регулярное выражение для поиска ключей кеша. Используйте $ в конце для точного совпадения.
Примеры:
# Purge конкретного размера
curl -X PURGE "http://localhost:2019/souin-api/souin/.*resize:fit:800.*photo\.jpg$"
# Purge всех вариантов одного изображения
curl -X PURGE "http://localhost:2019/souin-api/souin/.*example.com/photo.jpg"
# Purge всех изображений домена
curl -X PURGE "http://localhost:2019/souin-api/souin/.*example\.com.*"
Ответ: 204 No Content — успешно.
Purge всего кеша
curl -X PURGE http://localhost:2019/souin-api/souin/flush
Ответ: 204 No Content — успешно.
Формат ключа кеша
Souin формирует ключ кеша из HTTP-метода, схемы, хоста и пути:
{METHOD}-{scheme}-{host}:{port}-{path}
Пример:
GET-http-localhost:8888-/unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg
При purge по regex ищите совпадение по частям пути.
Примеры использования
curl
# Закешировать изображение
curl -s -o /dev/null -w "status: %{http_code}, time: %{time_total}s\n" \
"http://localhost:8888/unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg"
# → status: 200, time: 0.570s (MISS)
# Повторный запрос
curl -s -o /dev/null -w "status: %{http_code}, time: %{time_total}s\n" \
"http://localhost:8888/unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg"
# → status: 200, time: 0.001s (HIT)
# Purge
curl -X PURGE "http://localhost:2019/souin-api/souin/.*example.com/photo.jpg"
JavaScript
async function purgeCache(imageUrl: string) {
const response = await fetch(
`http://localhost:2019/souin-api/souin/.*${escapeRegex(imageUrl)}`,
{ method: 'PURGE' }
)
return response.ok
}
function escapeRegex(str: string): string {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
Безопасность
Caddy admin API по умолчанию доступен только на localhost:2019. В production:
- Порт 2019 не должен быть открыт наружу
- Можно настроить
admin offв Caddyfile и использовать альтернативный доступ - Или ограничить через firewall
Ограничения
- In-memory storage — по умолчанию кеш хранится в памяти. При перезапуске Caddy кеш теряется
- Для production рекомендуется подключить дисковый storage (Badger, NutsDB) через дополнительный плагин