Новинка Виртуальный VDS сервер в Финляндии от 390р
Выберите продукт

HTTP 103 Early Hints на практике: включаем в Nginx и Apache и ускоряем загрузку ассетов

HTTP 103 Early Hints — способ подтолкнуть браузер к загрузке CSS/JS/шрифтов до 200 OK. В гайде — что реально ускоряется, как отобрать preload-цели, включить в Apache, пробросить через Nginx, сгенерировать 103 в приложении и безопасно проверить профит в метриках.
HTTP 103 Early Hints на практике: включаем в Nginx и Apache и ускоряем загрузку ассетов

HTTP 103 Early Hints — это промежуточный ответ сервера, который приходит до окончательного 200/304 и содержит подсказки в заголовках Link с rel=preload. Браузер, получив такой сигнал, может начать сетевые запросы за критичными ресурсами (CSS, JS, шрифты) раньше, чем увидит HTML-документ. На практике это уменьшает простой сети на критическом пути и ускоряет FCP/LCP, особенно на длинных TTFB и при холодных кэших.

Зачем нам early hints в 2025-м

Исторически для ранней доставки ресурсов пробовали HTTP/2 Server Push. Но push сложнее, легко ошибиться с кэшированием, он снят из браузеров Chromium и не считается устойчивой оптимизацией. Early hints, наоборот, сохраняет управление у браузера: сервер лишь подсказывает, а клиент решает — выгружать ресурс или нет. Это безопаснее с точки зрения перегрева канала и проще для эксплуатации.

Ключевая мысль: early hints — это «мягкое ускорение». Мы не насильно «толкаем» байты, а даём браузеру право начать загрузку, если он считает это уместным. Ошибиться труднее, откат — банально убрать лишние Link.

Как работает 103 Early Hints (вкратце)

Последовательность выглядит так:

  1. Клиент отправляет запрос страницы.
  2. Сервер как можно раньше шлёт промежуточный ответ HTTP/2 103 или HTTP/1.1 103 и один или несколько заголовков Link с rel=preload.
  3. Браузер начинает грузить эти ресурсы параллельно подготовке основного ответа.
  4. Приходит финальный ответ (обычно 200 OK), страница продолжает рендер.

Поддержка у современных браузеров есть в Chromium-семействе и Safari; Firefox экспериментировал и может требовать флагов. Даже если конкретный клиент проигнорирует 103, финальные Link: preload в ответе 200 не мешают — они просто не дадут выигрыш настолько рано.

Схема: 103 Early Hints приходят до финального 200 OK

Какие ассеты реально стоит preload-ить

Ресурсы в 103 должны быть «на 100% понадобятся» сразу после старта рендеринга:

  • Критический CSS основного бандла: as=style.
  • Ключевой JS, без которого не работает above-the-fold: as=script.
  • Первичный webfont для заголовков/основного текста: as=font; type=font/woff2; crossorigin.

Аккуратно с картинками: они огромные и часто лениво подгружаются. Если у вас стабильный hero на первом экране, preload может помочь, но проверяйте метрики — иногда лучше fetchpriority=high в HTML.

Золотое правило: не более 3–6 ссылок в 103. Чем больше подсказок, тем выше шанс лишней конкуренции за TCP-оконце и рост блокировок при медленном канале.

Apache: включаем early hints за 5 минут

Apache умеет генерировать 103 на уровне веб-сервера. Вам понадобится mod_http2 и mod_headers. Проверьте, что HTTP/2 включён для виртуального хоста, и добавьте подсказки с атрибутом early.

# httpd.conf (или в конфиге vhost)
LoadModule http2_module modules/mod_http2.so
LoadModule headers_module modules/mod_headers.so

# Внутри виртуального хоста TLS
<VirtualHost *:443>
  ServerName example.com
  Protocols h2 http/1.1

  # Включаем генерацию 103
  H2EarlyHints On

  # Список preload через Link, именно для 103
  Header add Link "</assets/app.css>; rel=preload; as=style" early
  Header add Link "</assets/app.js>; rel=preload; as=script" early
  Header add Link "</fonts/Inter.woff2>; rel=preload; as=font; type=font/woff2; crossorigin" early

  DocumentRoot "/var/www/html"
</VirtualHost>

Пара замечаний:

  • early говорит mod_headers положить заголовок именно в 103, а не только в финальный ответ.
  • Если у вас динамика по ассетам (хеш в имени файла), поддерживайте шаблоны через переменные окружения/перегенерацию конфига при деплое.
  • Присваивайте корректный as и type — браузер использует их для планирования.

Если параллельно настраиваете безопасность, пригодится наш разбор про заголовки: HTTP Security Headers в Nginx и Apache.

Сгенерировать 103 из приложения за Apache

Apache также способен пробросить 103, если его сгенерировало приложение до финального ответа. Это полезно, когда список ассетов зависит от рендеринга.

# PHP (apache2handler). Работает только если фронтенд допускает 103
header('HTTP/1.1 103 Early Hints');
header('Link: </assets/app.css>; rel=preload; as=style', false);
header('Link: </assets/app.js>; rel=preload; as=script', false);
flush();

// Далее обычная отдача HTML
http_response_code(200);
echo '<!doctype html>...';

В php-fpm за прокси поведение зависит от фронтенда: не каждый сервер пробрасывает 103 дальше. Смотрите следующий раздел для Nginx.

Фрагмент конфигурации Apache с H2EarlyHints и Link early

Nginx и 103: реалистичные варианты

В чистом Nginx нет штатной директивы, которая «синтезирует» 103 из Link-списка, как это делает Apache. Практически применимы два пути:

  1. Приложение само отправляет 103 (Node.js, Go, некоторые фреймворки на Ruby/Java), а Nginx пробрасывает ответ клиенту.
  2. Nginx проксирует на Apache, который формирует 103, а Nginx выполняет роль фронтенда/балансера.

В обоих случаях важно протестировать, что конкретная версия Nginx в вашем окружении действительно пересылает промежуточные ответы 1xx клиенту. Клиентская сторона должна говорить по HTTP/2 или HTTP/3, иначе выгоды не будет.

# Пример reverse proxy Nginx перед Apache или приложением, которое шлёт 103
server {
  listen 443 ssl http2;
  server_name example.com;

  # TLS-настройки опущены

  location / {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_pass http://127.0.0.1:8080;
  }
}

Если у вас проект на собственном сервере, удобнее всего экспериментировать на VDS: полный доступ к конфигам Nginx/Apache и логам. Для HTTPS сразу подключайте SSL-сертификаты, иначе браузеры не включат HTTP/2/3 и профит от 103 будет минимальным. Для сравнения стеков и подходов также посмотрите материал Nginx vs Apache в 2025.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды Финляндия

Генерация 103 на уровне приложения (через Nginx)

Современные рантаймы позволяют отправлять 103 самостоятельно. Два рабочих примера:

// Node.js (18+) — Express-подобный обработчик
res.writeEarlyHints({
  Link: '</assets/app.css>; rel=preload; as=style, </assets/app.js>; rel=preload; as=script'
});
res.status(200).send('<!doctype html>...');
// Go (1.19+) — net/http
w.Header().Add("Link", "</assets/app.css>; rel=preload; as=style")
w.Header().Add("Link", "</assets/app.js>; rel=preload; as=script")
w.WriteHeader(103)
if f, ok := w.(http.Flusher); ok { f.Flush() }

// финальный ответ
w.WriteHeader(200)
w.Write([]byte("<!doctype html>..."))

Проверка: видит ли клиент 103

Самый простой способ — через curl и сетевой инспектор браузера.

# Сырой заголовочный обмен с HTTP/2
curl -I --http2 --raw https://example.com/

В корректной реализации вы увидите два блока статуса: сначала HTTP/2 103 с несколькими Link, затем финальный HTTP/2 200. В DevTools в разделе Network откройте запрос документа: Chrome показывает секцию «103 Early Hints» с теми же заголовками.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Как подбирать список Link: preload

Алгоритм, который хорошо себя показал в продакшене:

  1. Соберите критический путь от навигации до первого значимого рендера (FCP/LCP). Обычно это главный CSS и один-два JS-чанка.
  2. Проверьте кэшируемость: 103 особенно полезен при холодном кэше и на первой загрузке.
  3. Добавьте webfont только если он используется на первом экране и без него будет layout shift. Не забудьте crossorigin.
  4. Не preload-ьте ресурсы, которые могут не понадобиться на этой странице (динамические виджеты ниже фолда).
  5. Ограничьте объём: суммарный размер preload-ресурсов не должен забивать канал и мешать получению HTML.

В помощь с кэшированием статики — чеклист и примеры в статье Cache-Control и ETag для статики. Для кросс-доменных шрифтов/ассетов может пригодиться настройка CORS: CORS-заголовки в Nginx и Apache.

Метрики: что измерять и как интерпретировать

Целевые индикаторы при включении early hints:

  • Снижение FCP/LCP на медленных сетях и при высоком TTFB.
  • Уменьшение времени загрузки первого CSS-файла и главного JS-бандла.
  • Стабилизация рендеринга: меньше layout shift из-за шрифтов (если preload фонтов корректен).

Проводите A/B: часть трафика без 103, часть — с 103, одинаковые списки Link в 200. Ищите статистически значимое улучшение. Если дельта незаметна — возможно, у вас и так быстрый TTFB или ассеты уже в кэше.

Частые ошибки и подводные камни

  • Отсутствует as или указан неверно. Браузер может проигнорировать preload или ошибиться с приоритетами.
  • Шрифты без crossorigin. Для фонтов через Link: preload требуется crossorigin, иначе запрос пойдёт дважды.
  • Предзагрузка тяжёлых изображений, которые не участвуют в LCP. Это расходует бюджет канала, замедляя доставку HTML.
  • Дублирующиеся preload в 103 и в HTML. Само по себе не критично, но поддерживать сложнее; держите источник истины один.
  • Слишком много ссылок в 103. Ограничьте до самого необходимого.

Rollback и фичефлаг

Делайте включение 103 управляемым: флаг в конфиге Apache (H2EarlyHints On|Off) или переключатель на уровне приложения. В случае деградации сети/клиентов достаточно убрать секцию с Link early или перестать эмитить 103 из кода. Финальные Link на 200 можно оставить — они не навредят.

Чем early hints отличаются от HTTP/2 Push

Коротко: push пытался предугадать и «запихнуть» ресурс в клиент, часто мимо кэша и приоритетов, что приводило к избыточному трафику; браузеры его убрали. Early hints лишь подсказывают, какие запросы стоит начать раньше, на условиях клиента. Это делает оптимизацию предсказуемой, простой и совместимой с кэшем.

Итоги

HTTP 103 Early Hints — практичный способ ускорить загрузку критичных ассетов без тяжёлой инфраструктуры. Apache позволяет включить 103 буквально несколькими строками, а для Nginx рабочая стратегия — пробрасывать 103, сформированный приложением или бэкендом на Apache. Дисциплина в выборе ресурсов для preload и аккуратные эксперименты с метриками дадут ощутимый выигрыш в реальном UX без риска перегреть канал и усложнить поддержку.

Поделиться статьей

Вам будет интересно

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

После одновременной остановки всех узлов Galera обычного запуска MariaDB недостаточно. Сначала найдите сервер с последней транзакц ...
CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

Разберём, почему CoreDNS перезапускается или отвечает SERVFAIL, как обнаружить замкнутую пересылку DNS-запросов, проверить доступн ...
Apache Kafka KRaft на VDS: отдельные controller и broker

Apache Kafka KRaft на VDS: отдельные controller и broker

Соберём новый Kafka-кластер без ZooKeeper на шести Linux VDS: три узла controller образуют отказоустойчивый metadata quorum, а три ...