Опубликовано: 8 июня 2020 г.
WebTransport — это веб-API, использующий протокол HTTP/3 в качестве двунаправленного транспортного механизма. Он предназначен для двусторонней связи между веб-клиентом и HTTP/3-сервером. Он поддерживает отправку данных как ненадежным способом с помощью своих API дейтаграмм , так и надежным способом с помощью своих API потоков .
Дейтаграммы идеально подходят для отправки и получения данных, не требующих строгих гарантий доставки. Размер отдельных пакетов данных ограничен максимальным размером передаваемого блока (MTU) базового соединения, и они могут быть успешно переданы, а могут и не быть, а если и будут переданы, то могут прибыть в произвольном порядке. Эти характеристики делают API дейтаграмм идеальными для передачи данных с низкой задержкой и наилучшими усилиями. Дейтаграммы можно рассматривать как сообщения протокола UDP (User Datagram Protocol) , но зашифрованные и с управлением перегрузкой.
В отличие от них, API потоков обеспечивают надежную , упорядоченную передачу данных. Они хорошо подходят для сценариев, где необходимо отправлять или получать один или несколько потоков упорядоченных данных. Использование нескольких потоков WebTransport аналогично установлению нескольких TCP- соединений, но поскольку HTTP/3 использует более легковесный протокол QUIC , их можно открывать и закрывать с меньшими накладными расходами.
Варианты использования
Это небольшой список возможных способов использования WebTransport разработчиками.
- Отправка состояния игры на сервер через регулярные интервалы с минимальной задержкой в виде небольших, ненадежных сообщений, поступающих не по порядку.
- Приём медиапотоков, передаваемых с сервера с минимальной задержкой, независимо от других потоков данных.
- Получение уведомлений, отправляемых с сервера, пока веб-страница открыта.
We're interested in hearing more about how you plan to use WebTransport.
Поддержка браузеров
Как и в случае со всеми функциями, не имеющими универсальной поддержки браузеров, мы рекомендуем добавить функцию определения этих функций .
Взаимосвязь с другими технологиями
Можно ли считать WebTransport заменой WebSockets?
Возможно. Существуют сценарии, в которых WebSockets или WebTransport могут быть подходящими протоколами связи.
В сетях WebSocket обмен данными строится на основе единого, надежного и упорядоченного потока сообщений, что подходит для некоторых типов коммуникационных задач. Если вам необходимы эти характеристики, API потоков WebTransport также могут их обеспечить. В сравнении с ними, API дейтаграмм WebTransport обеспечивают доставку с низкой задержкой, без гарантий надежности или упорядоченности, поэтому они не являются прямой заменой WebSockets.
При использовании WebTransport с API дейтаграмм или нескольких одновременно работающих экземпляров Streams API вам не нужно беспокоиться о блокировке в начале очереди , что может быть проблемой с WebSockets. Кроме того, есть преимущества в производительности при установлении новых соединений, поскольку базовое рукопожатие QUIC происходит быстрее, чем запуск TCP через TLS.
WebTransport является частью нового проекта спецификации, и поэтому экосистема WebSocket, включающая клиентские и серверные библиотеки, стала гораздо более надежной. Если вам нужно что-то, что работает «из коробки» с распространенными серверными конфигурациями и имеет широкую поддержку веб-клиентов, WebSocket — лучший выбор на сегодняшний день.
WebTransport — это то же самое, что и API UDP-сокетов?
No. WebTransport is not a UDP Socket API . While WebTransport uses HTTP/3, which in turn uses UDP "under the hood," WebTransport has requirements around encryption and congestion control that make it more than a basic UDP Socket API.
Является ли WebTransport альтернативой каналам передачи данных WebRTC?
Да, для соединений клиент-сервер. WebTransport обладает многими теми же свойствами, что и каналы передачи данных WebRTC , хотя базовые протоколы отличаются.
Как правило, запуск HTTP/3-совместимого сервера требует меньше настройки и конфигурации, чем обслуживание WebRTC-сервера, которое включает в себя понимание множества протоколов ( ICE , DTLS и SCTP ) для обеспечения работоспособности транспортного уровня. WebRTC же включает в себя гораздо больше компонентов, что может привести к сбоям в согласовании клиент-серверных данных.
The WebTransport API was designed with the web developer use cases in mind, and should feel more like writing modern web platform code than using WebRTC's data channel interfaces. Unlike WebRTC , WebTransport is supported inside of Web Workers , which allows you to perform client-server communications independent of a given HTML page. Because WebTransport exposes a Streams -compliant interface, it supports optimizations around backpressure .
Однако, если у вас уже есть работающая клиент-серверная конфигурация WebRTC, которая вас устраивает, переход на WebTransport может не принести существенных преимуществ.
Эксперимент
Лучший способ поэкспериментировать с WebTransport — запустить совместимый HTTP/3-сервер. Используйте эту страницу с простым JavaScript-клиентом, чтобы проверить взаимодействие клиента и сервера.
Кроме того, на сайте webtransport.day доступен поддерживаемый сообществом эхо-сервер.
Используйте API
WebTransport был разработан на основе современных примитивов веб-платформы, таких как API Streams . Он в значительной степени опирается на промисы и хорошо работает с async и await .
Текущая реализация WebTransport в Chromium поддерживает три различных типа трафика: датаграммы, а также однонаправленные и двунаправленные потоки.
Подключиться к серверу
Для подключения к HTTP/3-серверу необходимо создать экземпляр WebTransport . URL-адрес должен иметь https . Номер порта необходимо указать явно.
Для ожидания установления соединения следует использовать промис ready . Этот промис остается невыполненным до завершения настройки и отклоняется, если соединение не удается установить на этапе QUIC/TLS.
Обещание closed выполняется, когда соединение закрывается нормально, и отклоняется, если закрытие было неожиданным.
Если сервер отклоняет соединение из-за ошибки, указанной клиентом (например, неверный путь URL), то соединение с параметром closed преобразуется в reject, а с ready оно остается неразрешенным.
const url = 'https://example.com:4999/foo/bar';
const transport = new WebTransport(url);
// Optionally, set up functions to respond to
// the connection closing:
transport.closed.then(() => {
console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
}).catch((error) => {
console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
});
// Once .ready fulfills, the connection can be used.
await transport.ready;
API датаграмм
После того как у вас будет создан экземпляр WebTransport, подключенный к серверу, вы можете использовать его для отправки и получения отдельных битов данных, известных как датаграммы .
Метод writeable getter` возвращает WritableStream , который веб-клиент может использовать для отправки данных на сервер. Метод readable getter` возвращает объект ` ReadableStream , позволяющий прослушивать данные с сервера. Оба потока по своей природе ненадежны, поэтому возможно, что записанные вами данные не будут получены сервером, и наоборот.
Оба типа потоков используют экземпляры Uint8Array для передачи данных.
// Send two datagrams to the server.
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);
// Read datagrams from the server.
const reader = transport.datagrams.readable.getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
// value is a Uint8Array.
console.log(value);
}
API потоков
После подключения к серверу вы также можете использовать WebTransport для отправки и получения данных через его API потоков.
Каждый фрагмент всех потоков представляет собой массив Uint8Array . В отличие от API Datagram, эти потоки надежны. Однако каждый поток независим, поэтому порядок данных между потоками не гарантируется.
WebTransportSendStream
Объект WebTransportSendStream создается веб-клиентом с помощью метода createUnidirectionalStream() экземпляра WebTransport , который возвращает промис для WebTransportSendStream .
Для закрытия связанного HTTP/3-потока используйте метод close() объекта WritableStreamDefaultWriter . Браузер попытается отправить все ожидающие данные, прежде чем фактически закрыть связанный поток.
// Send two Uint8Arrays to the server.
const stream = await transport.createUnidirectionalStream();
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('All data has been sent.');
} catch (error) {
console.error(`An error occurred: ${error}`);
}
Аналогично, используйте метод abort() объекта WritableStreamDefaultWriter для отправки запроса RESET_STREAM на сервер. При использовании abort() браузер может отбросить любые ожидающие данные, которые еще не были отправлены.
const ws = await transport.createUnidirectionalStream();
const writer = ws.getWriter();
writer.write(...);
writer.write(...);
await writer.abort();
// Not all the data may have been written.
WebTransportReceiveStream
Сервер инициирует вызов WebTransportReceiveStream . Получение объекта WebTransportReceiveStream для веб-клиента — это двухэтапный процесс. Сначала клиент вызывает атрибут incomingUnidirectionalStreams экземпляра WebTransport , который возвращает объект ReadableStream . Каждый фрагмент этого ReadableStream , в свою очередь, представляет собой объект WebTransportReceiveStream , который можно использовать для чтения экземпляров Uint8Array отправленных сервером.
async function readFrom(receiveStream) {
const reader = receiveStream.readable.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is a Uint8Array
console.log(value);
}
}
const rs = transport.incomingUnidirectionalStreams;
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is an instance of WebTransportReceiveStream
await readFrom(value);
}
You can detect stream closure using the closed promise of the ReadableStreamDefaultReader . When the underlying HTTP/3 stream is closed with the FIN bit , the closed promise is fulfilled after all the data is read. When the HTTP/3 stream is closed abruptly (for example, by RESET_STREAM ), then the closed promise rejects.
// Assume an active receiveStream
const reader = receiveStream.readable.getReader();
reader.closed.then(() => {
console.log('The receiveStream closed gracefully.');
}).catch(() => {
console.error('The receiveStream closed abruptly.');
});
WebTransportBidirectionalStream
Объект WebTransportBidirectionalStream может быть создан как сервером, так и клиентом.
Веб-клиенты могут создать его, используя метод createBidirectionalStream() экземпляра WebTransport , который возвращает промис для объекта WebTransportBidirectionalStream .
const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream
Вы можете прослушивать поток WebTransportBidirectionalStream созданный сервером с атрибутом incomingBidirectionalStreams экземпляра WebTransport , который возвращает объект ReadableStream . Каждый фрагмент этого ReadableStream , в свою очередь, является объектом WebTransportBidirectionalStream .
const rs = transport.incomingBidirectionalStreams;
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is a WebTransportBidirectionalStream
// value.readable is a ReadableStream
// value.writable is a WritableStream
}
WebTransportBidirectionalStream — это просто комбинация WebTransportSendStream и WebTransportReceiveStream . Примеры из предыдущих двух разделов объясняют, как использовать каждый из них.
Полиэфирный наполнитель
Доступен полифил (или, скорее, понифил, предоставляющий функциональность в качестве автономного модуля), называемый webtransport-ponyfill-websocket , который реализует некоторые возможности WebTransport. Внимательно ознакомьтесь с ограничениями в README проекта, чтобы определить, подходит ли это решение для вашего случая.
Вопросы конфиденциальности и безопасности
Для получения авторитетных рекомендаций см. соответствующий раздел проекта спецификации.
Обратная связь
Есть ли какие-либо неудобства или проблемы с API, которые не решены должным образом? Или, возможно, отсутствуют необходимые компоненты для реализации вашей идеи?
- Создайте заявку в репозитории Web Transport на GitHub или добавьте свои мысли к уже существующей заявке.
- Сообщите об ошибке в реализации Chromium . Укажите как можно больше подробностей, а также инструкции по воспроизведению.
Ваша публичная поддержка помогает Chrome расставлять приоритеты в разработке новых функций и показывает другим производителям браузеров, насколько важно их поддерживать.
- Напишите в Твиттере @ChromiumDev , используя хэштег
#WebTransportи подробно описав, где и как вы его используете.
Общее обсуждение
Для общих вопросов или проблем, не подпадающих под другие категории, вы можете использовать группу Google web-transport-dev .
Благодарности
Мы использовали информацию из документа WebTransport Explainer и проекта спецификации . Благодарим соответствующих авторов за предоставленную основу.