Оптимизация изображений
ONREZA автоматически оптимизирует изображения на лету — конвертирует в современные форматы (WebP, AVIF), изменяет размеры и применяет сжатие.
Как это работает
Заголовок раздела «Как это работает»Вместо прямых ссылок на изображения используйте специальный endpoint:
/_onreza/image?url=/images/photo.jpg&w=640&q=75Платформа автоматически:
- Берёт оригинальное изображение из вашего деплоя
- Нормализует размер, качество и blur на фиксированные ступени
- Конвертирует в WebP по умолчанию или в AVIF при
f=avif - Кэширует результат в объектное хранилище для быстрой доставки
Базовое использование
Заголовок раздела «Базовое использование»Простой пример
Заголовок раздела «Простой пример»<!-- Оригинал --><img src="/images/photo.jpg" alt="Photo" />
<!-- Оптимизированная версия 640px WebP --><img src="/_onreza/image?url=/images/photo.jpg&w=640" alt="Photo" />Параметры URL
Заголовок раздела «Параметры URL»| Параметр | Описание | Пример |
|---|---|---|
url |
Обязательный. Путь к изображению относительно корня | /images/photo.jpg |
w |
Обязательный. Ширина в пикселях, 1-4096. Значение нормализуется вверх до ближайшей ступени |
640 |
h |
Высота в пикселях, 1-4096. Если не указана — пропорционально |
480 |
q |
Качество сжатия (1-100). По умолчанию: 75; нормализуется к ближайшей ступени | 85 |
f |
Формат: webp или avif. По умолчанию: webp |
webp |
fit |
Режим обрезки: cover, contain, fill. По умолчанию: cover |
contain |
blur |
Gaussian blur (0-250). Для placeholder-ов; нормализуется к ближайшей ступени | 20 |
dpr |
Device Pixel Ratio (1-5). Для Retina дисплеев | 2 |
Нормализация размеров и качества
Заголовок раздела «Нормализация размеров и качества»Можно запрашивать любую ширину в диапазоне 1-4096 пикселей. ONREZA нормализует фактический размер вверх до ближайшей ступени, чтобы разные близкие URL-ы использовали один кэшированный вариант:
16, 32, 48, 64, 96, 128, 160, 192, 256, 320, 384, 512, 640, 768, 832, 1024, 1152, 1280, 1536, 1920, 2048, 2560, 3072, 3840, 4096
Качество нормализуется к ближайшей ступени: 50, 65, 75, 85, 95.
Blur нормализуется к ближайшей ступени: 0, 1, 2, 5, 10, 20, 40, 80, 160, 250.
Примеры использования
Заголовок раздела «Примеры использования»Responsive images с srcset
Заголовок раздела «Responsive images с srcset»<img src="/_onreza/image?url=/images/hero.jpg&w=640" srcset=" /_onreza/image?url=/images/hero.jpg&w=640 640w, /_onreza/image?url=/images/hero.jpg&w=1280 1280w, /_onreza/image?url=/images/hero.jpg&w=1920 1920w " sizes="(max-width: 768px) 640px, (max-width: 1200px) 1280px, 1920px" alt="Hero"/>AVIF с лучшим сжатием
Заголовок раздела «AVIF с лучшим сжатием»<picture> <source srcset="/_onreza/image?url=/images/photo.jpg&w=768&f=avif" type="image/avif" /> <source srcset="/_onreza/image?url=/images/photo.jpg&w=768&f=webp" type="image/webp" /> <img src="/_onreza/image?url=/images/photo.jpg&w=768" alt="Photo" /></picture>Thumbnail с обрезкой
Заголовок раздела «Thumbnail с обрезкой»<!-- Аватар 256×256, обрезка по центру --><img src="/_onreza/image?url=/images/avatar.jpg&w=256&h=256&fit=cover" width="256" height="256" alt="Avatar"/>Low Quality Image Placeholder (LQIP)
Заголовок раздела «Low Quality Image Placeholder (LQIP)»<img src="/_onreza/image?url=/images/hero.jpg&w=1920&q=85" style="background-image: url('/_onreza/image?url=/images/hero.jpg&w=64&blur=20&q=50'); background-size: cover;" alt="Hero"/>Retina/HiDPI изображения
Заголовок раздела «Retina/HiDPI изображения»<!-- Для дисплеев 2x запрашивается 512px-вариант, отображается как 256px --><img src="/_onreza/image?url=/images/logo.png&w=256&dpr=2" width="256" height="128" alt="Logo"/>S3 Cache
Заголовок раздела «S3 Cache»Оптимизированные изображения автоматически кэшируются в объектном хранилище для мгновенной доставки при повторных запросах.
Ключ кэша
Заголовок раздела «Ключ кэша»Кэш строится по хэшу оригинального изображения и нормализованным параметрам варианта: ширине, высоте, качеству, формату, режиму обрезки и blur. URL-ы, которые нормализуются в один набор параметров, используют один кэшированный вариант.
TTL кэша
Заголовок раздела «TTL кэша»| Тип | TTL |
|---|---|
| Оптимизированные изображения | 1 год |
| Оригиналы | Не кэшируются в объектном хранилище (берутся из деплоя) |
Безопасность
Заголовок раздела «Безопасность»SSRF Protection
Заголовок раздела «SSRF Protection»Image Optimization service защищён от SSRF (Server-Side Request Forgery) атак:
- Только relative URL: Параметр
urlдолжен начинаться с/ - Path Traversal Protection: Запрещены последовательности
..,%2e,%252e - URL Whitelist: Ограничен доступ только к изображениям из вашего деплоя
Проверка путей
Заголовок раздела «Проверка путей»// Запрещённые пути (вернут 400 Bad Request)/_onreza/image?url=https://evil.com/image.jpg // Абсолютный URL/_onreza/image?url=//evil.com/image.jpg // Protocol-relative URL/_onreza/image?url=/../../etc/passwd // Path traversal/_onreza/image?url=/..%2f..%2fsecret.txt // URL-encoded traversalПрограммная генерация URL
Заголовок раздела «Программная генерация URL»Для программной генерации URL используйте небольшой helper в приложении:
const IMAGE_WIDTHS = [ 16, 32, 48, 64, 96, 128, 160, 192, 256, 320, 384, 512, 640, 768, 832, 1024, 1152, 1280, 1536, 1920, 2048, 2560, 3072, 3840, 4096,] as const;
function normalizedWidth(width: number) { return IMAGE_WIDTHS.find((candidate) => candidate >= width) ?? 4096;}
function imageUrl(src: string, options: { width: number; quality?: number; format?: "webp" | "avif" }) { const params = new URLSearchParams({ url: src, w: String(normalizedWidth(options.width)), q: String(options.quality ?? 75), });
if (options.format) params.set("f", options.format);
return `/_onreza/image?${params}`;}Responsive component (пример)
Заголовок раздела «Responsive component (пример)»function responsiveImage(src: string, alt: string, sizes = '100vw') { const widths = [640, 1280, 1920]; const srcset = widths .map((width) => `${imageUrl(src, { width, quality: 85 })} ${width}w`) .join(", ");
return `<img src="${imageUrl(src, { width: 1280 })}" srcset="${srcset}" sizes="${sizes}" alt="${alt}" loading="lazy" decoding="async" />`;}Интеграция с фреймворками
Заголовок раздела «Интеграция с фреймворками»Next.js
Заголовок раздела «Next.js»Создайте кастомный loader:
export default function onrezaLoader({ src, width, quality }: { src: string; width: number; quality?: number;}) { const params = new URLSearchParams(); params.set('url', src); params.set('w', width.toString()); params.set('q', (quality || 75).toString()); return `/_onreza/image?${params.toString()}`;}
// next.config.jsmodule.exports = { images: { loader: 'custom', loaderFile: './onreza-image-loader.ts', },};Используйте стандартный <Image> компонент:
import Image from 'next/image';
<Image src="/images/photo.jpg" width={768} height={576} alt="Photo"/>Используйте <Image> компонент с кастомным endpoint:
---import { Image } from 'astro:assets';---
<Image src="/images/photo.jpg" width={640} height={480} alt="Photo" inferSize/>Или напрямую:
<img src="/_onreza/image?url=/images/photo.jpg&w=640" alt="Photo" width="640" height="480"/>Ограничения
Заголовок раздела «Ограничения»| Параметр | Лимит |
|---|---|
| Максимальный размер оригинала | 20 MB |
| Ширина и высота | 1-4096, нормализуются до ближайшей ступени вверх |
| Ступени качества | 50, 65, 75, 85, 95 |
| Ступени blur | 0, 1, 2, 5, 10, 20, 40, 80, 160, 250 |
| Максимальный DPR | 5 |
| Максимальный blur | 250 |
| Входные форматы | JPEG, PNG, GIF, WebP |
| Выходные форматы | WebP, AVIF |
Troubleshooting
Заголовок раздела «Troubleshooting»“Width out of range”
Заголовок раздела «“Width out of range”»Используйте ширину от 1 до 4096 пикселей. Значение будет нормализовано вверх до ближайшей кэшируемой ступени.
“Source image exceeds max size”
Заголовок раздела «“Source image exceeds max size”»Оригинальное изображение больше 20 MB. Оптимизируйте оригинал перед загрузкой.
“url must be a relative path”
Заголовок раздела «“url must be a relative path”»Параметр url должен быть относительным путём (начинаться с /), не полным URL.
“Path traversal detected”
Заголовок раздела «“Path traversal detected”»Обнаружена попытка path traversal. Убедитесь, что путь не содержит .. или подобных последовательностей.
Советы по производительности
Заголовок раздела «Советы по производительности»- Используйте srcset — позвольте браузеру выбрать оптимальный размер
- AVIF для тяжёлых изображений — используйте
f=avifявно, когда важно максимальное сжатие - Lazy loading — добавляйте
loading="lazy"для изображений ниже fold - Размеры — всегда указывайте
widthиheightдля предотвращения layout shift - DPR — используйте
dpr=2для Retina дисплеев, но не злоупотребляйте высокими значениями
См. также
Заголовок раздела «См. также»- Runtime API — текущий публичный runtime contract
- Compute Apps — серверный runtime для SSR и приложений
- Кастомные домены — для красивых URL изображений