WebTransport API

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

安全上下文: 此功能仅在安全上下文(HTTPS)中可用,且支持此功能的浏览器数量有限。

注意:此功能在 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 的基础上包含额外数据。

js
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 向其写入数据,以传输到服务器。

js
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 对象,您可以使用它从服务器接收数据。

js
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,以允许将数据写入流并发送到服务器。

js
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 类,因此可以以相同的方式使用。

js
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() 来读取它们。

js
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 的引用。它包含 readablewritable 属性,分别返回可用于读取和写入服务器的 WebTransportReceiveStreamWebTransportSendStream 实例的引用。

注意: WebTransportBidirectionalStream 类似于 WebTransportDatagramDuplexStream,不同之处在于,在该接口中,readablewritable 属性分别是 ReadableStreamWritableStream

js
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 读取可以按如下方式完成:

js
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 写入数据可以按如下方式完成:

js
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 实例,如上所示。但是,与单向示例一样,您需要一个初始函数来首先读取双向流。

js
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

浏览器兼容性

另见