HTTP/2 Server Push задумывался как «магия», которая ускорит первый визит: сервер предугадывает, какие ресурсы понадобятся, и отправляет их до запроса. По факту идея оказалась сложной в эксплуатации и непредсказуемой для кэша. Поддержка постепенно вымывается: в браузерах фича отключена или нестабильна, в HTTP/3 от неё отказались. Что теперь делать админам, девопсам и веб-мастерам, которым важна производительность? Ответ: перейти на связку декларативных подсказок (preload), современной приоритизации и грамотного кэширования.
Коротко: что случилось с HTTP/2 Push
Причины отказа — практические. Push порождал дубликаты трафика при попадании в существующий кэш браузера, плохо вписывался в реальные цепочки прокси и CDN, усложнял дебаг и часто не давал прогнозируемого выигрыша в метриках. В HTTP/3 концепцию убрали, а индустрия сместилась в сторону декларативных подсказок клиенту и нового протокольного механизма приоритизации.
Итог: вместо «угадывания» на стороне сервера — явное объявление критических ресурсов, корректные приоритеты и сильный кэш, который делает повторные визиты мгновенными.
Почему Push не взлетел: уроки
- Кэш-коллизии: если ресурс уже в кэше, серверный Push зря расходует канал.
- Хрупкость цепочки: TLS-терминация, прокси и CDN по-разному обращаются с Push, часть данных просто не доходила.
- Непрозрачность: waterfall в браузере неочевиден, отладка сложнее, регрессии — реальны.
- Трудозатраты: поддержка конфигурации Push в релизном цикле стоила дороже, чем альтернативы.
- Неуниверсальность: Push не знал контекста клиента (кэш, DPR, предпочтения, вариации по Vary), что приводило к неэффективным отправкам.
Новая тройка: preload, приоритизация и кэш
Сейчас ставка делается на:
- Link preload — явное объявление критически важных ресурсов до парсинга HTML.
- Приоритизация — протокольная (RFC 9218, заголовок
Priority
) и клиентские подсказки (fetchpriority
) для выверенного порядка загрузки. - Кэш — агрессивное и предсказуемое кеширование статики (Cache-Control, immutable, SWR), плюс версионирование по хэшу.
Link rel="preload": когда он действительно нужен
Preload полезен для ресурсов, которые:
- критичны для рендера первого экрана (Critical CSS, главный JS-бандл, LCP-изображение);
- нужны раньше, чем браузер успеет их обнаружить при парсинге HTML;
- загружаются из того же источника (меньше латентности и риска CORS-ошибок).
Рекомендации:
- Всегда указывайте корректный
as
(например,as=style
,as=script
,as=font
,as=image
). Браузер опирается на это для приоритета и политики безопасности. - Для шрифтов добавляйте
crossorigin
и используйтеfont-display
в CSS (частоswap
), чтобы не блокировать текст. - Не перегружайте страницу десятками preload — это выродится в конкуренцию за канал. Выбирайте 2–5 действительно критичных ресурсов.
- Держите декларации в одном месте: либо в HTML-голове, либо присылайте заголовком ответа
Link
. Дублирование мешает поддержке.
Link: </assets/app.css>; rel=preload; as=style
Link: </assets/runtime.js>; rel=preload; as=script
Link: </assets/lcp-hero.jpg>; rel=preload; as=image; imagesrcset="/assets/lcp-hero@2x.jpg 2x"
HTML-эквивалент:
<link rel="preload" href="/assets/app.css" as="style">
<link rel="preload" href="/assets/runtime.js" as="script">
<link rel="preload" href="/assets/lcp-hero.jpg" as="image" imagesrcset="/assets/lcp-hero@2x.jpg 2x">
103 Early Hints: полезно, когда бэкенд тяжёлый
Early Hints (статус 103) позволяют отдать заголовки Link: rel=preload
ещё до финального ответа 200/302/… Это особенно помогает при высоком TTFB (дорогие запросы к БД, холодный кеш приложения). Браузер начинает качать критичные ассеты параллельно, и к моменту отрисовки они уже в полёте или закешированы.
Нюансы внедрения:
- Проверьте, как ваша цепочка (балансировщик, прокси, CDN, веб-сервер, фреймворк) относится к промежуточным статусам. Часть компонентов далёко не всегда корректно форвардит 103.
- Отлаживайте в DevTools: ищите блок «Early Hints» и убедитесь, что preload реально стартовал до ответа.
- Не превращайте 103 в «мини-CDN-конфиг»: публикуйте только действительно критичные ресурсы.
На собственном VDS проще включить и контролировать 103, приоритизацию и заголовки кеширования централизованно. Для TLS-терминации используйте корректные SSL-сертификаты, чтобы не упираться в рукопожатия.

Приоритизация: Priority header и fetchpriority
Историческая приоритизация потоков в HTTP/2 была несовершенной; индустрия перешла к схеме RFC 9218 с заголовком Priority
. Идея: клиент и сервер согласуют «срочность» (urgency) и инкрементальную доставку. Дополнительно в HTML появился атрибут fetchpriority
для явного приоритета отдельных ресурсов.
Практика:
- LCP-изображение:
fetchpriority="high"
в HTML и, при возможности, ответ сервера сPriority
(высокая срочность). - Нефолдовые изображения и ассеты аналитики: низкий приоритет (
fetchpriority="low"
или низкая срочность вPriority
), плюс кеширование. - CSS — всегда высокий приоритет, JS — в зависимости от роли (инициализация рендера vs. виджеты ниже фолда).
<img src="/assets/hero.jpg" width="1200" height="630" fetchpriority="high" alt="...">
<img src="/assets/gallery-3.jpg" loading="lazy" fetchpriority="low" alt="...">
Серверный заголовок (пример для статики с высокой срочностью):
Priority: u=0, i
Где u
— срочность (0 — выше, 7 — ниже), i
— инкрементальная доставка. Браузеры постепенно расширяют поддержку этой схемы и используют её и в HTTP/2, и в HTTP/3.
Resource Hints: preconnect и dns-prefetch
Если часть критичных ресурсов уходит на внешние источники, сокращайте сетевую латентность заранее:
preconnect
— установка TCP/TLS ещё до первого запроса к домену.dns-prefetch
— только резолв DNS (менее затратный, но и менее полезный).
<link rel="preconnect" href="//cdn.example" crossorigin>
<link rel="dns-prefetch" href="//cdn.example">
Не перегибайте: избыточный preconnect
может зря открыть слишком много соединений.
Кэш как главный ускоритель
Сильный кэш убирает из цепочки почти всё, что не меняется на каждом запросе. Ключевые элементы:
- Долгий TTL + immutable для версионированной статики (имена с хэшем:
app.3f1a9d.css
). - Стратегия ревалидции для динамики:
ETag
,Last-Modified
,stale-while-revalidate
,stale-if-error
. - Правильный Vary (Accept-Encoding, DPR и т. п.), чтобы кэш не смешивал несовместимые варианты.
- Brotli для текстовых форматов и условное кеширование HTML на прокси, если это безопасно для персонализации.
# Пример локации Nginx для статики с долгим TTL и immutable
location ~* \.(css|js|mjs|woff2|jpg|jpeg|png|webp|avif|svg)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
Важно: если не используете имена с хэшем, нельзя ставить большой TTL и immutable
— клиенты не увидят обновления. Подробно про практики см. разделы версионирование по хэшу для S3/CDN и Cache-Control и ETag на практике.

План миграции с HTTP/2 Push
- Отключите Push в конфигурации веб-сервера/CDN. Уберите устаревшие директивы и плагины, чтобы не было «тихих» отправок.
- Постройте критический путь рендера: какие ресурсы нужны для первого экрана? Смотрите на LCP и FCP.
- Добавьте preload для выбранных 2–5 ресурсов. Проверьте, что
as
иcrossorigin
корректны, а сами ресурсы доступны. - Настройте приоритеты: используйте
fetchpriority
в разметке, а на сервере — заголовокPriority
там, где это оправдано. - Включите сильный кэш: версионирование по хэшу, долгий TTL,
immutable
. Для HTML — консервативные значения и ревалидация. - Экспериментируйте с 103 Early Hints, если TTFB высок. Следите, чтобы промежуточная инфраструктура не «съедала» 103.
- Промерьте эффект по LCP/FCP/TTFB, сравните waterfall, проверьте отсутствие дубликатов запросов и регрессий.
Частые ошибки и как их избежать
- Preload без
as
. Браузер теряет контекст и может понизить приоритет или запросить ресурс повторно. - Шрифт без
crossorigin
. Получите двойные запросы или CORS-ошибки. - Избыточный preload всего подряд. Итог — перегруженный конвейер, рост TTFB для HTML и ухудшение LCP.
- Несогласованность кэша: большой TTL без версионирования. Пользователи не видят обновления.
- Дублирование Link-заголовков и тэгов в HTML. Содержите объявление ресурсов в одном месте.
- Преждевременный preconnect ко множеству внешних доменов. Откроете лишние TCP/TLS, зря перегреете сокеты.
Как измерять эффект: прагматика
Смотрите на метрики, которые действительно отражают пользовательский опыт:
- LCP — основная целевая метрика. Preload LCP-изображения и приоритизация дают самый заметный эффект.
- FCP — растёт при корректном preload CSS и раннем старте загрузки шрифтов (с безблокирующим
font-display
). - TTFB — может визуально «расти» при агрессивном preload на одном сокете, но это не обязательно плохо, если LCP/FCP улучшаются.
Обязательно сравнивайте waterfall «до/после»: порядок запуска запросов, приоритеты, отметки Early Hints, попадания в кэш, размеры и сжатие. Делайте канареечный релиз на части трафика и проверяйте регрессии.
Примеры минимальных настроек
HTML: LCP-изображение и CSS
<link rel="preload" href="/assets/app.css" as="style">
<link rel="preload" href="/assets/hero.jpg" as="image" imagesrcset="/assets/hero@2x.jpg 2x">
<img src="/assets/hero.jpg" width="1200" height="630" fetchpriority="high" alt="...">
Заголовки ответов: Priority и Cache-Control
Priority: u=0, i
Cache-Control: public, max-age=31536000, immutable
ETag: "A1B2C3"
Vary: Accept-Encoding
Nginx: статическая раздача и приоритет (пример)
location = /assets/hero.jpg {
add_header Priority "u=0, i" always;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(css|js|mjs)$ {
add_header Priority "u=1" always;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
Если нужен полный контроль над веб-сервером, логично разворачивать проект на VDS: там проще выставить приоритеты, включить 103 и тонко настроить кэш.
Чек-лист перед продом
- Удалён весь код HTTP/2 Push и отключены соответствующие плагины/директивы.
- Критичный путь определён, для 2–5 ресурсов настроен preload.
- LCP-изображение помечено
fetchpriority="high"
, шрифты имеютcrossorigin
иfont-display
. - Статика версионирована по хэшу, для неё включены долгий TTL и
immutable
. - Приоритеты расставлены (заголовок
Priority
и/илиfetchpriority
), негативных побочных эффектов не обнаружено. - 103 Early Hints протестирован в вашей инфраструктуре там, где это действительно ускоряет.
- Измерения показали улучшение LCP/FCP и отсутствие регрессий.
Итог
Классический HTTP/2 Push ушёл — и это хорошая новость. Его место заняли более предсказуемые и управляемые механизмы: декларативный preload, современная приоритизация и сильный кэш. Вместе они дают стабильный выигрыш на первом визите и обеспечивают почти мгновенные повторные заходы. Потратьте день на переезд — и перестаньте «угадывать» за браузер: объявляйте критические ресурсы явно, расставляйте приоритеты и давайте клиентам кэшировать то, что не меняется.