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

148 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`.
### Список закешированных ключей
```bash
curl http://localhost:2019/souin-api/souin/
```
Ответ — JSON-массив ключей:
```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)
```bash
curl -X PURGE "http://localhost:2019/souin-api/souin/.*example.com/photo.jpg"
```
`regex` — регулярное выражение для поиска ключей кеша. Используйте `$` в конце для точного совпадения.
Примеры:
```bash
# 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 всего кеша
```bash
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
```bash
# Закешировать изображение
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
```ts
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) через дополнительный плагин