Фотография быстро движущегося транспорта.

Экспериментируем с WebTransport

WebTransport — это новый API, предлагающий двунаправленный обмен сообщениями между клиентом и сервером с малой задержкой. Узнайте больше о вариантах его использования и о том, как оставить отзыв для будущей реализации.

Published on Updated on

Translated to: English, 한국어, 中文, 日本語

Caution

Это предложение продолжает меняться в течение периода испытаний по схеме Origin. Возможны расхождения между реализацией в браузере и информацией в этой статье.

Чтобы узнать последнюю информацию об этом развивающемся предложении, прочтите редакционный черновик WebTransport.

Как только предложение стабилизируется, мы обновим эту статью и связанные с ней образцы кода, добавив самую свежую информацию.

Общая информация

Что такое WebTransport?

WebTransport — это веб-API, использующий протокол HTTP/3 в качестве двунаправленной коммуникации. Он предназначен для двусторонней связи между веб-клиентом и сервером HTTP/3. Этот интерфейс поддерживает отправку данных как ненадежно через API-интерфейсы датаграмм, так и надежно через API-интерфейсы потоков.

Датаграммы идеально подходят для отправки и получения данных, для которых не требуются строгие гарантии доставки. Отдельные пакеты данных ограничены по размеру максимальной единицей передачи (MTU) нижележащего соединения. Их передача может быть успешной или неудачной, а в случае успеха пакеты могут прибыть в произвольном порядке. Благодаря этим характеристикам API-интерфейсы датаграмм отлично подходят для передачи данных с максимально доступным качеством и минимальными задержками. Датаграммы можно рассматривать как сообщения протокола пользовательских датаграмм (UDP), но зашифрованные и адаптируемые к перегрузкам.

API-интерфейсы потоков, напротив, обеспечивают надежную упорядоченную передачу данных. Они хорошо подходят для сценариев, когда вам нужно отправить или получить один или несколько потоков упорядоченных данных. Использование нескольких потоков WebTransport аналогично установлению нескольких TCP-соединений, но поскольку HTTP/3 использует за кадром более легкий протокол QUIC, их можно открывать и закрывать без особых затрат.

Сценарии использования

Вот небольшой список возможных способов использования WebTransport разработчиками.

  • Отправка данных о состоянии игры через регулярные интервалы с минимальной задержкой на сервер с помощью небольших ненадежных неупорядоченных сообщений.
  • Получение потоков мультимедиа, отправленных с сервера, с минимальной задержкой и независимо от других потоков данных.
  • Получение уведомлений, отправленных с сервера, когда веб-страница открыта.

В рамках процесса испытаний по схеме Origin Trial мы хотели бы узнать больше о том, как вы планируете использовать WebTransport.

Со многими концепциями из этого предложения ранее проводились эксперименты в рамках испытаний по схеме Origin Trial более ранней версии QuicTransport, которая не была выпущена как часть Chrome.

WebTransport помогает в тех же сценариях использования, что и QuicTransport, с основным отличием в том, что основным транспортным протоколом является HTTP/3, а не QUIC.

Связь WebTransport с другими технологиями

Является ли WebTransport заменой WebSockets?

Возможно. Существуют сценарии использования, когда допустимыми протоколами связи могут быть WebSockets или WebTransport.

Связь WebSockets моделируется на основе единого надежного упорядоченного потока сообщений, что подходит для некоторых типов коммуникационных потребностей. Если вам нужны эти характеристики, их также могут предоставить API-интерфейсы потоков WebTransport. Для сравнения, API-интерфейсы датаграмм WebTransport обеспечивают доставку с малой задержкой, без гарантий надежности или порядка, поэтому они не являются прямой заменой WebSockets.

Используя WebTransport через API датаграмм или через несколько параллельных экземпляров API потоков, вы можете не беспокоиться о проблеме блокировки заголовка, которая может возникать при использовании WebSockets. Кроме того, есть преимущества в производительности при установлении новых соединений, поскольку базовое квитирование QUIC выполняется быстрее, чем запуск TCP через TLS.

WebTransport является частью новой черновой спецификации, и поэтому экосистема WebSocket вокруг клиентских и серверных библиотек в настоящее время намного более надежна. Если вам нужно готовое решение с общими настройками сервера и широкой поддержкой веб-клиентов, на данный момент лучшим выбором будет WebSockets.

WebTransport — это то же самое, что и UDP Socket API?

Нет. WebTransport не является UDP Socket API. В то время как WebTransport использует HTTP/3, который, в свою очередь, за кадром использует UDP, у WebTransport есть требования к шифрованию и контролю перегрузки, которые выводят его за рамки простого API-интерфейса UDP Socket.

Является ли WebTransport альтернативой каналам данных WebRTC?

Да, для клиент-серверных соединений. WebTransport имеет многие из тех же свойств, что и каналы данных WebRTC, хотя лежащие в основе протоколы отличаются.

Каналы данных WebRTC поддерживают одноранговую связь, но WebTransport поддерживает только соединение клиент-сервер. Для нескольких клиентов, которым необходимо напрямую общаться друг с другом, WebTransport не будет жизнеспособной альтернативой.

Как правило, для запуска HTTP/3-совместимого сервера требуется меньше настроек, чем для обслуживания сервера WebRTC, что предполагает понимание нескольких протоколов (ICE, DTLS и SCTP) для получения рабочего транспорта. WebRTC включает в себя гораздо больше движущихся частей, которые могут привести к неудачным переговорам между клиентом и сервером.

API WebTransport был разработан с учетом вариантов использования веб-разработчиками, так что работа с ним должна больше походить на написание кода современной веб-платформы, чем на использование интерфейсов каналов данных WebRTC. В отличие от WebRTC, WebTransport поддерживается внутри веб-воркеров, что позволяет вам выполнять обмен данными между клиентом и сервером независимо от данной HTML-страницы. Поскольку WebTransport предоставляет интерфейс, совместимый с потоками, он поддерживает оптимизацию контроля обратного потока.

Однако, если у вас уже есть работающая конфигурация WebRTC клиент/сервер, которая вас устраивает, переход на WebTransport может не дать особых преимуществ.

Попробуйте сами

Лучший способ поэкспериментировать с WebTransport — запустить совместимый сервер HTTP/3 локально. (К сожалению, публичный эталонный сервер, совместимый с последней спецификацией, в настоящее время недоступен.) Затем вы можете использовать эту страницу с базовым клиентом JavaScript, чтобы опробовать связь клиент/сервер.

Использование API

WebTransport был разработан на основе примитивов современных веб-платформ, таких как Streams API. Он в значительной степени полагается на обещания и хорошо работает с async и await.

Испытания по схеме Origin Trial WebTransport поддерживают три различных типа трафика: датаграммы, однонаправленные и двунаправленные потоки.

Подключение к серверу

Вы можете подключиться к серверу HTTP/3, создав экземпляр WebTransport. Схема URL должна быть https. Номер порта нужно указать явно.

Вы должны использовать обещание ready, чтобы дождаться установления соединения. Это обещание не будет выполнено до завершения настройки и будет отклонено, если соединение не будет установлено на этапе QUIC/TLS.

Обещание closed выполняется, когда соединение закрывается нормально, и отклоняется, если закрытие было неожиданным.

Если сервер отклоняет соединение из-за ошибки индикации клиента (например, путь URL-адреса недействителен), то это приводит к отклонению closed, а обещание ready остается неразрешенным.

const url = 'https://example.com:4999/foo/bar';
const transport = new WebTransport(url);

// По желанию, настраиваем функции для ответа
// на закрытие соединения:
transport.closed.then(() => {
console.log(`Соединение HTTP/3 с ${url} закрыто должным образом.`);
}).catch((error) => {
console.error('Соединение HTTP/3 с ${url} закрыто из-за ошибки: ${error}.');
});

// Когда .ready выполнится, соединение можно использовать.
await transport.ready;

API датаграмм

Если у вас есть экземпляр WebTransport, подключенный к серверу, вы можете использовать его для отправки и получения дискретных битов данных, известных как датаграммы.

Получатель writeable возвращает WritableStream, который веб-клиент может использовать для отправки данных на сервер. Получатель readable возвращает ReadableStream, позволяя вам прослушивать данные с сервера. Оба потока по своей природе ненадежны, поэтому возможно, что данные, которые вы записываете, не будут получены сервером, и наоборот.

Оба типа потоков используют экземпляры Uint8Array для передачи данных.

// Посылаем на сервер две датаграммы.
const writer = transport.datagrams.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);

// Считываем датаграммы с сервера.
const reader = transport.datagrams.readable.getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
// Значение представляет собой Uint8Array.
console.log(value);
}

Chrome в настоящее время не предоставляет асинхронный итератор для ReadableStream. На данный момент лучшим способом чтения из потока является использование getReader() сочетании с while().

API потоков

После подключения к серверу вы также можете использовать WebTransport для отправки и получения данных через его API потоков.

Каждый фрагмент всех потоков — это массив Uint8Array. В отличие от API датаграмм, эти потоки надежны. Но каждый поток независим, поэтому порядок данных в потоках не гарантируется.

SendStream

SendStream создается веб-клиентом с помощью метода createSendStream() экземпляра WebTransport, который возвращает обещание для SendStream.

Используйте метод close(), принадлежащий WritableStreamDefaultWriter, чтобы закрыть связанное соединение HTTP/3. Браузер пытается отправить все ожидающие данные, прежде чем фактически закрыть связанное соединение.

// Посылаем два массива Uint8Array на сервер.
const stream = await transport.createSendStream();
const writer = stream.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
try {
await writer.close();
console.log('Все данные отправлены.');
} catch (error) {
console.error(`Произошла ошибка: ${error}`);
}

Точно так же используйте метод abort(), принадлежащий WritableStreamDefaultWriter, для отправки QUIC RESET_STREAM на сервер. При использовании abort() браузер может отбросить все ожидающие данные, которые еще не были отправлены.

const ws = await transport.createSendStream();
const writer = ws.getWriter();
writer.write(...);
writer.write(...);
await writer.abort();
// Возможно, были записаны не все данные.

ReceiveStream

ReceiveStream инициируется сервером. Получение ReceiveStream — двухэтапный процесс для веб-клиента. Сначала он вызывает метод receiveStreams() экземпляра WebTransport, который возвращает ReadableStream. Каждый фрагмент этого ReadableStream, в свою очередь, является ReceiveStream, который можно использовать для чтения экземпляров Uint8Array, отправленных сервером.

async function readFrom(receiveStream) {
const reader = receiveStream.readable.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// Значение представляет собой Uint8Array
console.log(value);
}
}

const rs = transport.receiveStreams();
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// Значение представляет собой ReceiveStream
await readFrom(value);
}

Вы можете обнаружить закрытие потока, используя обещание closed, принадлежащее ReadableStreamDefaultReader. Когда базовое соединение HTTP/3 закрывается битом FIN, обещание closed выполняется после чтения всех данных. Когда соединение HTTP/3 внезапно закрывается (например, с помощью STREAM_RESET), обещание closed отклоняется.

// Предполагаем активный receiveStream
const reader = receiveStream.readable.getReader();
reader.closed.then(() => {
console.log('receiveStream закрыт должным образом.');
}).catch(() => {
console.error('receiveStream закрыт неожиданно.');
});

BidirectionalStream

BidirectionalStream может быть создан сервером или клиентом.

Веб-клиенты могут создать его, используя метод createBidirectionalStream() экземпляра WebTransport, который возвращает обещание для BidirectionalStream.

const stream = await transport.createBidirectionalStream();
// stream представляет собой BidirectionalStream
// stream.readable представляет собой ReadableStream
// stream.writable представляет собой WritableStream

Вы можете прослушивать BidirectionalStream, созданный сервером, с помощью метода receiveBidirectionalStreams() экземпляра WebTransport, который возвращает ReadableStream. Каждый фрагмент этого ReadableStream, в свою очередь, является BidirectionalStream.

const rs = transport.receiveBidrectionalStreams();
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value представляет собой BidirectionalStream
// value.readable представляет собой ReadableStream
// value.writable представляет собой WritableStream
}

BidirectionalStream — это просто комбинация SendStream и ReceiveStream. В примерах из двух предыдущих разделов поясняется, как использовать их использовать.

Дополнительные примеры

Черновик спецификации WebTransport включает ряд дополнительных встроенных примеров, а также полную документацию по всем методам и свойствам.

WebTransport в Chrome DevTools

К сожалению, поддержка Chrome DevTools для WebTransport к моменту запуска испытаний по схеме Origin Trial не готова. Вы можете пометить эту проблему в Chrome, чтобы получать уведомления об обновлениях интерфейса DevTools.

Вопросы конфиденциальности и безопасности

См. соответствующий раздел проекта спецификации для получения авторитетных указаний.

Отзывы

Команда Chrome хочет узнать ваши мнения и впечатления от использования этого API на протяжении всего периода испытаний.

Отзывы о структуре API

Есть ли в API что-то неудобное или работающее не так, как вы ожидали? Может быть, отсутствуют какие-то элементы, необходимые для реализации вашей идеи?

Отправьте сообщение о проблеме в репозиторий GitHub для Web Transport или добавьте свой комментарий к существующей теме.

Проблема с реализацией?

Вы нашли ошибку в реализации Chrome?

Сообщите об ошибке на https://new.crbug.com. Укажите как можно больше подробностей и простые инструкции по воспроизведению.

Планируете использовать этот API?

Ваша публичная поддержка помогает команде Chrome определять приоритет функций и показывает важность их поддержки разработчикам других браузеров.

  • Обязательно подпишитесь на отчет о ходе испытаний Origin Trial, указав свой домен и контактную информацию. Так вы покажете, что заинтересованы в этом интерфейсе.
  • Упомяните в твите @ChromiumDev, поставьте хэштег #WebTransport и подробно расскажите, где и как вы используете этот API.

Обсуждение

Вы можете использовать группу Google web-transport-dev для решения общих вопросов или проблем, которые не попадают ни в одну из других категорий.

Благодарности

Эта статья включает информацию из пояснительного документа WebTransport, черновой спецификации и связанных проектных документов. Благодарим их авторов за предоставленные основы.

Баннер для этой статьи взят у Робина Пьера на Unsplash.

Updated on Improve article

This site uses cookies to deliver and enhance the quality of its services and to analyze traffic. If you agree, cookies are also used to serve advertising and to personalize the content and advertisements that you see. Learn more about our use of cookies.