Skip to content
32 / 41

Что такое HTTP/2 Server Push?


Полный ответ

Как Server Push работает:

JavaScript
Без Server Push:                    С Server Push:
Браузер         Сервер              Браузер         Сервер
|  |                  |  |
| -- GET / ------> |                  | -- GET / ------> |
| <-- HTML ------- |                  | <-- HTML ------- |
|  |                  |<-- PUSH style.css (без запроса!)
| [парсит HTML] |                  |<-- PUSH app.js   (без запроса!)
|  |                  |  |
| -- GET style.css-> |               | [парсит HTML] |
| <-- style.css -- |                  | [CSS и JS уже получены]
| -- GET app.js --> |                 |  |
| <-- app.js ----- |                  |  |

Настройка на nginx (исторически):

Nginx

# nginx.conf (требует ngx_http_v2_module)
server {
    listen 443 ssl http2;

    location = / {
        http2_push /css/style.css;
        http2_push /js/app.js;
        http2_push /img/logo.webp;
    }
}

JavaScript
// Node.js с http2 модулем
import http2 from 'node:http2';
import fs from 'node:fs';

const server = http2.createSecureServer({
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.crt'),
  });

server.on('stream', (stream, headers) => {
    if (headers[':path'] === '/') {

      // Push CSS до отправки HTML
      stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
          if (err) return;
          pushStream.respond({ 'content-type': 'text/css', ':status': 200 });
          pushStream.end(fs.readFileSync('public/style.css'));
        });

      // Отправляем HTML
      stream.respond({ 'content-type': 'text/html', ':status': 200 });
      stream.end(fs.readFileSync('public/index.html'));
    }
  });

Почему Server Push провалился:

JavaScript
Проблема 1: Не знает о кеше браузера
Сервер пушит style.css каждый раз
Даже если у браузера уже есть свежая копия в кеше
Результат: трата трафика и bandwidth

Проблема 2: Приоритизация
Push-ресурсы конкурируют с основным HTML за bandwidth
Если запушить слишком много, HTML придёт медленнее
Парадокс: пытаемся ускорить, а замедляем

Проблема 3: Сложность конфигурации
Нужно точно знать, какие ресурсы понадобятся
Динамические страницы усложняют это многократно
Ошибки в конфигурации ухудшают производительность

Современные альтернативы:

HTML
<!-- Альтернатива 1: preload -- браузер запрашивает сам, но с приоритетом -->
<link rel="preload" href="/css/style.css" as="style">
<link rel="preload" href="/js/app.js" as="script">
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>

JavaScript
Альтернатива 2: 103 Early Hints

Браузер                  Сервер
|  |
| -- GET / --------------> |
| <-- 103 Early Hints ---- |  (мгновенно, пока сервер готовит HTML)
|    Link: </style.css>; rel=preload
|    Link: </app.js>; rel=preload
|  |
| [браузер уже грузит |
  | style.css и app.js] |  [сервер готовит HTML]
|  |
| <-- 200 OK + HTML ------ |
| [CSS и JS уже загружены или почти]

Nginx

# nginx с 103 Early Hints
location = / {
    add_header Link "</css/style.css>; rel=preload; as=style" early;
    add_header Link "</js/app.js>; rel=preload; as=script" early;
    proxy_pass http://backend;
}

📌 Реальные кейсы

Почему Chrome убрал Server Push:

JavaScript
Данные Chrome (2022):
-- Менее 1.25% HTTP/2 страниц использовали Server Push
-- В большинстве случаев Push ухудшал или не влиял на метрики
-- 103 Early Hints покрывает те же сценарии без проблем с кешем
-- Поддержка Server Push удалена из Chrome начиная с версии 106

Когда Server Push имел смысл (исторически):

JavaScript
-- Первый визит пользователя (пустой кеш)
-- Известный набор критических ресурсов
-- Медленный бэкенд (пока сервер думает, можно пушить статику)

Сейчас все эти случаи покрываются 103 Early Hints лучше

Резюме

Server Push был многообещающей фичей HTTP/2, но на практике не оправдал ожиданий из-за проблем с кешированием и приоритизацией. Chrome удалил его поддержку. Современные альтернативы: <link rel="preload"> для контроля из HTML и 103 Early Hints для серверной подсказки. Не стоит тратить время на настройку Server Push в новых проектах.

Что такое HTTP/2 Server Push? | JScriptiser