WebTransport API
注意:此功能在 Web Workers 中可用。
WebTransport API 提供了一个对 WebSockets 的现代化更新,通过 HTTP/3 传输 在客户端和服务器之间传输数据。WebTransport 支持多路流、单向流和乱序传输。它通过 流 (streams) 实现可靠传输,并通过类 UDP 的数据报实现不可靠传输。
概念与用法
HTTP/3 自 2018 年以来一直在开发中。它基于 Google 的 QUIC 协议(该协议本身基于 UDP),并修复了经典 TCP 协议(HTTP 和 WebSockets 基于该协议)的几个问题。
这些问题包括:
- 队头阻塞 (Head-of-line blocking)
-
HTTP/2 允许多路复用,因此单个连接可以同时传输多个资源。但是,如果一个资源失败,该连接上的所有其他资源都会被阻塞,直到丢失的数据包被重传。使用 QUIC,只有失败的资源会受到影响。
- 更快的性能
-
在许多方面,QUIC 的性能优于 TCP。QUIC 可以独立处理安全功能,而不是将其责任推给 TLS 等其他协议,这意味着更少的往返。而且流比旧的数据包机制提供了更高的传输效率。这可以带来显著的改进,尤其是在高延迟的网络上。
- 更好的网络切换
-
QUIC 使用唯一的连接 ID 来处理每个请求的源和目标——以确保数据包正确送达。此 ID 可以在不同网络之间持续存在,这意味着,例如,如果您从 Wi-Fi 切换到移动网络,下载可以继续进行而不会中断。另一方面,HTTP/2 使用 IP 地址作为标识符,因此网络切换可能会有问题。
- 不可靠传输
-
HTTP/3 支持通过数据报进行不可靠数据传输。
WebTransport API 提供对通过 HTTP/3 进行双向通信的低级访问,利用上述优点,并支持可靠和不可靠的数据传输。
初始连接
要打开与 HTTP/3 服务器的连接,请将服务器的 URL 传递给 WebTransport() 构造函数。请注意,方案必须是 HTTPS,并且端口号必须明确指定。一旦 WebTransport.ready Promise 变为 fulfilled,您就可以开始使用该连接了。
另请注意,您可以通过等待 WebTransport.closed Promise 变为 fulfilled 来响应连接关闭。WebTransport 操作返回的错误是 WebTransportError 类型,并且在标准 DOMException 的基础上包含额外数据。
const url = "https://example.com:4999/wt";
async function initTransport(url) {
// Initialize transport connection
const transport = new WebTransport(url);
// The connection can be used once ready fulfills
await transport.ready;
// …
}
// …
async function closeTransport(transport) {
// Respond to connection closing
try {
await transport.closed;
console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
} catch (error) {
console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
}
}
通过数据报进行不可靠传输
“不可靠”意味着数据传输不被保证,也不会按特定顺序到达。在某些情况下,这没问题,而且可以提供非常快速的传输。例如,您可能希望传输定期的游戏状态更新,其中每个消息都会覆盖最后一个到达的消息,并且顺序不重要。
通过 WebTransport.datagrams 属性处理不可靠数据传输——该属性返回一个 WebTransportDatagramDuplexStream 对象,其中包含发送数据报到服务器并接收它们所需的一切。
WebTransportDatagramDuplexStream.writable 属性返回一个 WritableStream 对象,您可以使用 writer 向其写入数据,以传输到服务器。
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);
WebTransportDatagramDuplexStream.readable 属性返回一个 ReadableStream 对象,您可以使用它从服务器接收数据。
async function readData() {
const reader = transport.datagrams.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
// value is a Uint8Array.
console.log(value);
}
}
通过流进行可靠传输
“可靠”意味着数据传输和顺序是保证的。这提供了更慢的传输(尽管比 WebSockets 快),并且在可靠性和顺序很重要的场合(例如聊天应用程序)是必需的。
在使用通过流进行可靠传输时,您还可以设置同一传输上不同流的相对优先级。
单向传输
要从用户代理打开单向流,请使用 WebTransport.createUnidirectionalStream() 方法获取指向 WritableStream 的引用。您可以从中 获取 writer,以允许将数据写入流并发送到服务器。
async function writeData() {
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}`);
}
}
另请注意,一旦所有数据都已发送,可以使用 WritableStreamDefaultWriter.close() 方法关闭关联的 HTTP/3 连接。
如果服务器打开单向流向客户端传输数据,则可以在客户端通过 WebTransport.incomingUnidirectionalStreams 属性访问它,该属性返回一个包含 WebTransportReceiveStream 对象的 ReadableStream。这些可以用于读取服务器发送的 Uint8Array 实例。
在这种情况下,首先要做的就是设置一个函数来读取 WebTransportReceiveStream。这些对象继承自 ReadableStream 类,因此可以以相同的方式使用。
async function readData(receiveStream) {
const reader = receiveStream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
// value is a Uint8Array
console.log(value);
}
}
接下来,调用 WebTransport.incomingUnidirectionalStreams 并获取对它返回的 ReadableStream 上可用的 reader 的引用,然后使用 reader 从服务器读取数据。每个块都是一个 WebTransportReceiveStream,我们使用前面设置的 readFrom() 来读取它们。
async function receiveUnidirectional() {
const uds = transport.incomingUnidirectionalStreams;
const reader = uds.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
// value is an instance of WebTransportReceiveStream
await readData(value);
}
}
双向传输
要从用户代理打开双向流,请使用 WebTransport.createBidirectionalStream() 方法获取指向 WebTransportBidirectionalStream 的引用。它包含 readable 和 writable 属性,分别返回可用于读取和写入服务器的 WebTransportReceiveStream 和 WebTransportSendStream 实例的引用。
注意: WebTransportBidirectionalStream 类似于 WebTransportDatagramDuplexStream,不同之处在于,在该接口中,readable 和 writable 属性分别是 ReadableStream 和 WritableStream。
async function setUpBidirectional() {
const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a WebTransportReceiveStream
const readable = stream.readable;
// stream.writable is a WebTransportSendStream
const writable = stream.writable;
// …
}
从 WebTransportReceiveStream 读取可以按如下方式完成:
async function readData(readable) {
const reader = readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
// value is a Uint8Array.
console.log(value);
}
}
向 WebTransportSendStream 写入数据可以按如下方式完成:
async function writeData(writable) {
const writer = writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
}
如果服务器打开双向流以向客户端传输数据并从客户端接收数据,则可以通过 WebTransport.incomingBidirectionalStreams 属性访问它,该属性返回一个包含 WebTransportBidirectionalStream 对象的 ReadableStream。每个对象都可以用于读写 Uint8Array 实例,如上所示。但是,与单向示例一样,您需要一个初始函数来首先读取双向流。
async function receiveBidirectional() {
const bds = transport.incomingBidirectionalStreams;
const reader = bds.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
// value is an instance of WebTransportBidirectionalStream
await readData(value.readable);
await writeData(value.writable);
}
}
接口
WebTransport-
提供功能,使用户代理能够连接到 HTTP/3 服务器,在任一方向或两个方向上发起可靠和不可靠的传输,并在不再需要连接时关闭连接。
WebTransportBidirectionalStream-
表示由服务器或客户端创建的双向流,可用于可靠传输。它提供对用于读取传入数据的
ReadableStream和用于写入传出数据的WritableStream的访问。 WebTransportDatagramDuplexStream-
表示一个双工流,可用于客户端和服务器之间数据报的不可靠传输。它提供对用于读取传入数据报的
ReadableStream、用于写入传出数据报的WritableStream以及与流相关的各种设置和统计信息的访问。 WebTransportError-
表示与 WebTransport API 相关的错误,该错误可能源于服务器错误、网络连接问题或客户端发起的中止操作(例如,由
WritableStream.abort()调用引起)。 WebTransportReceiveStream-
为传入的 WebTransport 单向或双向
WebTransport流提供流功能。 WebTransportSendStream-
为传出的 WebTransport 单向或双向
WebTransport流提供流功能。
示例
有关完整示例,请参阅:
规范
| 规范 |
|---|
| WebTransport # web-transport |
浏览器兼容性
加载中…