Files
image-gateway/docs/cache-api.md
S.Gromov 0751c4b469 feat: добавить Image Gateway с кешем Souin
- добавлена сборка Caddy с Souin, Otter и NutsDB

- добавлена конфигурация dev, prod и test Docker Compose

- настроено кеширование через Otter L1 и NutsDB L2

- добавлены e2e-тесты Bun для кеша, restart и purge

- добавлена документация по запуску, API кеша и тестам
2026-05-04 12:18:37 +03:00

4.5 KiB
Raw Permalink Blame History

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) через дополнительный плагин