- Оригинальный адрес:Node.js can HTTP/2 push!
- Оригинальный автор:Node.js Foundation
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Raoul1996
- Корректор:Starriers,FateZeros,LeviDing
Node.js может выполнять HTTP/2 push!
Эта статья из@nearFormГлавный архитектор, член технического руководящего комитета Node.jsMatteo Collinaи инженер-программист GoogleJinwoo Leeв соавторстве.
посколькуиюль 2017 г.С момента появления HTTP/2 в Node.js эта практика претерпела несколько улучшений. Теперь мы почти готовы убрать флаг «экспериментальный». Конечно, лучше попробовать поддержку HTTP/2 с Node.js версии 9, так как в этой версии есть последние исправления и улучшения.
Самый простой способ начать работу — использовать те, которые представлены в новом разделе основного модуля http2.Слой совместимости:
const http2 = require('http2');
const options = {
key: getKeySomehow(),
cert: getCertSomehow()
};
// 必须使用 https
// 不然浏览器无法连接
const server = http2.createSecureServer(options, (req, res) => {
res.end('Hello World!');
});
server.listen(3000);
Уровень совместимости обеспечивает иrequire('http')
Тот же высокоуровневый API (с тем же прослушивателем запросов для объектов запроса и ответа), обеспечивающий плавный переход на HTTP/2.
Уровень совместимости также обеспечивает простой путь обновления для авторов веб-фреймворков.Restifyа такжеFastifyОба реализуют поддержку HTTP/2 на основе уровня совместимости Node.js HTTP/2.
FastifyЯвляетсяновый веб-фреймворк, который фокусируется на производительности, не жертвуя продуктивностью разработчиков и не отбрасывая недавниеОбновление до версии 1.0.0богатая экосистема плагинов.
Использовать HTTP/2 с fastify очень просто:
const Fastify = require('fastify');
// 必须使用 https
// 不然浏览器无法连接
const fastify = Fastify({
http2: true, // 译者注:原文作者这里少了逗号
https: {
key: getKeySomehow(),
cert: getCertSomehow()
}
});
fastify.get('/fastify', async (request, reply) => {
return 'Hello World!';
});
server.listen(3000);
Хотя один и тот же код приложения может быть запущен на HTTP/1.1 и HTTP/2 для выбора протокола, отдельный совместимый уровень не предоставляет некоторых более мощных функций, поддерживаемых HTTP/2. Базовый модуль HTTP2 может получать новые базовые API-интерфейсы через прослушиватель «stream».Http2Stream), чтобы использовать эти дополнительные функции:
const http2 = require('http2');
const options = {
key: getKeySomehow(),
cert: getCertSomehow()
};
// 必须使用 https
// 不然浏览器无法连接
const server = http2.createSecureServer(options);
server.on('stream', (stream, headers) => {
// 流是双工的
// headers 是一个包含请求头的对象
// 响应将把 headers 发到客户端
// meta headers 用冒号(:)开头
stream.respond({ ':status': 200 });
// 这是 stream.respondWithFile()
// 和 stream.pushStream()
stream.end('Hello World!');
});
server.listen(3000);
В Fastify к Http2Stream можно получить доступ через API request.raw.stream следующим образом:
fastify.get('/fastify', async (request, reply) => {
request.raw.stream.pushStream({
':path': '/a/resource'
}, function (err, stream) {
if (err) {
request.log.warn(err);
return
}
stream.respond({ ':status': 200 });
stream.end('content');
});
return 'Hello World!';
});
HTTP/2 Push — возможности и проблемы
HTTP/2 значительно повышает производительность на основе HTTP/1,Пуш сервераявляется одним из его главных достижений.
Типичный (или упрощенный) поток HTTP-запросов и ответов будет выглядеть следующим образом (скриншот ниже — ссылка на Hack News):
- Браузер запрашивает HTML-документ.
- Сервер обрабатывает запрос, генерирует и отправляет HTML-документы.
- Браузер получает ответ и анализирует HTML-документ.
- Браузеры будут отправлять больше запросов (чтобы получить эти ресурсы) для получения дополнительных ресурсов, необходимых во время рендеринга HTML-документа, таких как таблицы стилей, изображения, файлы JavaScript и т. д.
- Сервер отвечает на запросы для каждого ресурса.
- Браузер использует HTML-документ и связанные с ним ресурсы для отображения страницы.
Это означает, что для рендеринга HTML-документа часто требуется несколько запросов и ответов, так как браузеру нужны дополнительные ресурсы, связанные с ним, для правильного рендеринга документа. Было бы здорово, если бы эти связанные ресурсы можно было отправлять в браузер вместе с исходным HTML-документом, не требуя от браузера их запроса. Это именно то, для чего нужен сервер HTTP/2.
В HTTP/2 сервер может активно отвечать на первоначальный запрос дополнительными ресурсами, которые, по его мнению, браузер запросит позже.толкать. Если позже браузеру действительно потребуются эти дополнительные ресурсы, он просто будет использовать уже загруженные ресурсы и не будет отправлять дополнительные запросы. Например, предположим, что сервер отправляет этот файл /index.html
<!DOCTYPE html>
<html>
<head>
<title>Awesome Unicorn!</title>
<link rel="stylesheet" type="text/css" href="/static/awesome.css">
</head>
<body>
This is an awesome Unicorn! <img src="/static/unicorn.png">
</body>
</html>
Сервер ответит на запрос, отправив обратно этот файл. Но он знает, что /index.html нужны /static/awesome.css и /static/unicorn.png для правильного отображения. Итак, сервер отправляет эти файлы вместе с /index.html.
for (const asset of ['/static/awesome.css', '/static/unicorn.png']) {
// stream 是 ServerHttp2Stream。
stream.pushStream({':path': asset}, (err, pushStream) => {
if (err) throw err;
pushStream.respondWithFile(asset);
});
}
На стороне клиента, когда браузер анализирует /index.html, он говорит, что ему нужны /static/awesome.css и /static/unicorn.png, но браузер знает, что они были отправлены и сохранены в кэше! Таким образом, ему не нужно отправлять два дополнительных запроса, а он использует уже пропушенные ресурсы.
Это звучит неплохо. Но есть некоторые проблемы (трудности). Во-первых, серверу не так просто узнать, какие дополнительные ресурсы использовать для исходного запроса. Хотя мы можем поместить это решение на прикладной уровень, столь же трудно позволить разработчику принять решение. Один из способов — вручную проанализировать HTML, чтобы узнать список необходимых ресурсов. Но по мере выполнения итераций приложения и обновления HTML-файлов ведение этого списка может быть утомительным и подверженным ошибкам.
Другая проблема возникает из-за кэширования ранее извлеченных ресурсов внутри браузера. Используя приведенный выше пример, если браузер загрузил /index.html вчера, он также загрузит /static/unicorn.png, и этот файл обычно кэшируется в браузере. Когда браузер загружает /index.html, а затем пытается загрузить /static/unicorn.png, он знает, что последний уже закеширован, и просто использует его, вместо того, чтобы запрашивать его снова. В этом случае, если сервер отправляет /static/unicorn.png, он будет тратить пропускную способность. Таким образом, у сервера должен быть какой-то способ определить, был ли ресурс кэширован в браузере.
Будут другие типы проблем, иПрактические правила для отправки документов через HTTP/2дождитесь этих.
Автоматическая отправка HTTP/2
Чтобы облегчить разработчикам Node.js поддержку функции push на стороне сервера, Google выпустила пакет npm для автоматизации:h2-auto-push. Он предназначен для обработки вышеперечисленных иПрактические правила для отправки документов через HTTP/2многие из упомянутых проблем.
Он отслеживает шаблон запросов от браузера и определяет дополнительные ресурсы, связанные с исходно запрошенным ресурсом. Впоследствии, если запрашивается исходный ресурс, соответствующий ресурс будет автоматически передан в браузер. Он также оценит, мог ли браузер кэшировать ресурс, и пропустит отправку, если это так.
h2-auto-push разработан как промежуточное ПО для использования различными веб-фреймворками. В качестве промежуточного программного обеспечения для обслуживания статических файлов очень легко разработать промежуточное программное обеспечение для автоматической отправки с использованием этого пакета npm. Например см.fastify-auto-push. Это автоматическая отправка и использование HTTP/2.h2-auto-pushупаковкаfastifyплагин.
Также очень легко использовать это промежуточное ПО в вашем приложении.
const fastify = require('fastify');
const fastifyAutoPush = require('fastify-auto-push');
const fs = require('fs');
const path = require('path');
const {promisify} = require('util');
const fsReadFile = promisify(fs.readFile);
const STATIC_DIR = path.join(__dirname, 'static');
const CERTS_DIR = path.join(__dirname, 'certs');
const PORT = 8080;
async function createServerOptions() {
const readCertFile = (filename) => {
return fsReadFile(path.join(CERTS_DIR, filename));
};
const [key, cert] = await Promise.all(
[readCertFile('server.key'), readCertFile('server.crt')]);
return {key, cert};
}
async function main() {
const {key, cert} = await createServerOptions();
// 浏览器只支持 https 使用 HTTP/2。
const app = fastify({https: {key, cert}, http2: true});
// 新建并注册自动推送插件
// 它应该注册在中间件链的一开始。
app.register(fastifyAutoPush.staticServe, {root: STATIC_DIR});
await app.listen(PORT);
console.log(`Listening on port ${PORT}`);
}
main().catch((err) => {
console.error(err);
});
Просто, верно?
Наши тесты показывают, что h2-auto-push повышает производительность на 12 % по сравнению с HTTP/2 и примерно на 135 % по сравнению с HTTP/1. Мы надеемся, что эта статья помогла вам лучше понять HTTP2 и преимущества, которые он может принести вашему приложению, включая HTTP2 push.
Отдельное спасибо NearForm'sJames SnelземляDavid Mark Clementsи GoogleAli Sheikhа такжеKelvin JinМожет помочь отредактировать этот пост в блоге. Большое спасибо GoogleMatt LoringНачальные усилия в автоматическом толчке.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.