Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Экспериментальная поддержка HTTP/3 уже встроена в основные браузеры и начинает потихоньку пробираться на сервера. А это значит, что уже можно полностью отказаться от использования в своих nodejs
-приложениях от http-библиотеки и переключиться на http2. Насколько же отличается реализация http2
-сервера от обычного http
-сервера?
Под катом пример простого web-приложения, выполняющего типовые задачи (получение статики GET'ом, upload файлов, POST-запросы, server sent events) на серверах HTTP/1 и HTTP/2. HTTP/2 Server Push в данном примере не затрагивался. Приложение не использует внешних зависимостей (npm
-пакетов), всё сделано при помощи собственного функционала nodejs
.
Описание web-приложения
Клиентская часть - это ./index.html и ./favicon.ico (куда ж без него!). Раздача статики серверами - обычный GET-запрос. Функционал клиента позволяет загрузить файл на сервер (upload), получить список файлов (SSE - сервер передаёт клиенту имя одного файла раз в 200 мсек.), удалить выбранные файлы с сервера (типовой POST-запрос).
Запросы клиента обслуживают HTTP/1 и HTTP/2 серверы на портах 4010 и 4020. Каждый сервер реализован в собственном файле (./http1.mjs и ./http2.mjs), общий код вынесен в библиотеку ./lib.mjs. Оба сервера используют один и тот же каталог для хранения загруженных файлов.
Чтобы попробовать приложение, нужно склонировать на свой компьютер github-репозиторий flancer64/habr_node_http_servers и запустить сервера:
$ node http1.mjs &
$ node http2.mjs &
Точки входа в приложение:
http://localhost:4010/index.html
https://localhost:4020/index.html
Так как для доступа к HTTP/2-серверу через браузер нужно использовать шифрование (https), а сертификат в тестовом приложении самоподписной, то при первом входе на HTTP/2-сервер высвечивается предупреждение браузера, которое можно игнорить.
Резюме
Внезапно оказалось, что в nodejs
для этих 4-функций (GET, POST, upload, SSE) различий на уровне кода между HTTP/1 и HTTP/2 нет. Вернее, единственное различие - это способ создания сервера. Вот код для HTTP/1:
import {createServer} from 'http';
import {onRequest} from './lib.mjs';
const server = createServer();
server.listen(4010);
server.on('error', (err) => console.dir(err));
server.on('request', onRequest);
А это код для HTTP/2:
import {createSecureServer} from 'http2';
import {readFileSync} from 'fs';
import {onRequest} from './lib.mjs';
const server = createSecureServer({
key: readFileSync('key.pem'),
cert: readFileSync('cert.pem')
});
server.listen(4020);
server.on('error', (err) => console.dir(err));
server.on('request', onRequest);
Всё, далее оба сервера используют один и тот же библиотечный код (функция onRequest
), реализующий backend-логику web-приложения.
Как бы, это довольно очевидно: HTTP/2 является развитием HTTP/1 и базируется на принципе "запрос - ответ":
В случае с SSE получается, что ответ состоит из фрагментов и растянут во времени:
Этот базовый принцип отличает протокол HTTP (полудуплекс - сначала передача, потом приём) от WebSocket, который является полнодуплексным (приём и передача информации осуществляется независимо):
Но для меня стало неожиданным, что между http
и http2
библиотеками в nodejs
есть такая качественная обратная совместимость - просто выноси бизнес-логику отдельно и используй её на http или http2-сервере по своему желанию.
"That's all I have to say about that" (c)