Перейти к содержимому

Оптимизация изображений

ONREZA автоматически оптимизирует изображения на лету — конвертирует в современные форматы (WebP, AVIF), изменяет размеры и применяет сжатие.

Вместо прямых ссылок на изображения используйте специальный endpoint:

/_onreza/image?url=/images/photo.jpg&w=640&q=75

Платформа автоматически:

  1. Берёт оригинальное изображение из вашего деплоя
  2. Нормализует размер, качество и blur на фиксированные ступени
  3. Конвертирует в WebP по умолчанию или в AVIF при f=avif
  4. Кэширует результат в объектное хранилище для быстрой доставки
<!-- Оригинал -->
<img src="/images/photo.jpg" alt="Photo" />
<!-- Оптимизированная версия 640px WebP -->
<img src="/_onreza/image?url=/images/photo.jpg&w=640" alt="Photo" />
Параметр Описание Пример
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.

<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"
/>
<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>
<!-- Аватар 256×256, обрезка по центру -->
<img
src="/_onreza/image?url=/images/avatar.jpg&w=256&h=256&fit=cover"
width="256"
height="256"
alt="Avatar"
/>
<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"
/>
<!-- Для дисплеев 2x запрашивается 512px-вариант, отображается как 256px -->
<img
src="/_onreza/image?url=/images/logo.png&w=256&dpr=2"
width="256"
height="128"
alt="Logo"
/>

Оптимизированные изображения автоматически кэшируются в объектном хранилище для мгновенной доставки при повторных запросах.

Кэш строится по хэшу оригинального изображения и нормализованным параметрам варианта: ширине, высоте, качеству, формату, режиму обрезки и blur. URL-ы, которые нормализуются в один набор параметров, используют один кэшированный вариант.

Тип TTL
Оптимизированные изображения 1 год
Оригиналы Не кэшируются в объектном хранилище (берутся из деплоя)

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 используйте небольшой 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}`;
}
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"
/>`;
}

Создайте кастомный loader:

onreza-image-loader.ts
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.js
module.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

Используйте ширину от 1 до 4096 пикселей. Значение будет нормализовано вверх до ближайшей кэшируемой ступени.

Оригинальное изображение больше 20 MB. Оптимизируйте оригинал перед загрузкой.

Параметр url должен быть относительным путём (начинаться с /), не полным URL.

Обнаружена попытка path traversal. Убедитесь, что путь не содержит .. или подобных последовательностей.

  1. Используйте srcset — позвольте браузеру выбрать оптимальный размер
  2. AVIF для тяжёлых изображений — используйте f=avif явно, когда важно максимальное сжатие
  3. Lazy loading — добавляйте loading="lazy" для изображений ниже fold
  4. Размеры — всегда указывайте width и height для предотвращения layout shift
  5. DPR — используйте dpr=2 для Retina дисплеев, но не злоупотребляйте высокими значениями