WebTransport

W3C 候选推荐标准快照,

关于本文档的更多信息
此版本:
https://www.w3.org/TR/2026/CR-webtransport-20260730/
最新发布版本:
https://www.w3.org/TR/webtransport/
编辑草案:
https://w3c.github.io/webtransport/
历史:
https://www.w3.org/standards/history/webtransport/
反馈:
public-webtransport@w3.org 主题行请注明 “[webtransport] … 消息主题 …” (邮件存档)
GitHub
规范内标注
编辑:
Nidhi Jaju (Google)
Victor Vasiliev (Google)
Jan-Ivar Bruaroey (Mozilla)
前任编辑:
Bernard Aboba (Microsoft Corporation)
Peter Thatcher (Google)
Robin Raymond (Optical Tone Ltd.)
Yutaka Hirano (Google)

摘要

本文档在 WebIDL 中定义了一组 ECMAScript API,用于在浏览器与服务器之间发送和接收数据,利用 [WEB-TRANSPORT-OVERVIEW]。 本规范与 IETF WEBTRANS 工作组制定的协议规范协同开发。

本文档状态

本节描述本文档发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准与草案索引中找到。

本文档由 WebTransport 工作组 使用推荐标准 轨道发布为候选推荐标准快照。本文档旨在成为 W3C 推荐标准。 为确保有机会进行广泛审查,本文档将至少在 之前 保持候选推荐标准状态。

欢迎对本文档提出反馈和意见。请在本文档的 问题跟踪器中提交问题, 该问题跟踪器位于本文档的 GitHub 仓库中。

发布为候选推荐标准并不意味着获得 W3C及其成员的认可。 候选推荐标准快照已经过广泛审查,旨在 收集实现经验,并且工作组成员已承诺为相关实现提供免版税许可

本文档退出候选推荐标准阶段的标准是,至少有两个独立且可互操作的用户代理 实现本规范的所有特性,这将通过是否通过工作组开发的测试套件中定义的 用户代理测试来确定。工作组将编制一份实现报告以跟踪进展。

这一即将发布的推荐标准的未来更新可能会纳入新特性

本文档由一个依据 W3C 专利政策运作的工作组制定。 W3C 维护着一份与该工作组 交付成果相关的所有专利披露公开列表; 该页面还包含披露专利的说明。 任何实际知悉某项专利,并认为该专利包含必要权利要求的个人, 都必须依照 W3C 专利政策第 6 节披露相关信息。

本文档受 2025年8月18日 W3C 流程文档管辖。

1. 简介

本节为非规范性内容。

本规范使用 [WEB-TRANSPORT-OVERVIEW] 向服务器发送和接收数据。它的用法类似于 WebSockets,但支持多路流、单向流、乱序传输,以及可靠和不可靠的传输方式。

注意: 本规范中提供的 API 代表了基于 IETF WEBTRANS WG 正在进行的工作的初步提案。 由于 [WEB-TRANSPORT-HTTP3][WEB-TRANSPORT-HTTP2] 规范仍在制定中,因此协议和 API 都可能会在未来发生重大变化。

2. 一致性

除了标记为非规范性的章节外,本规范中的所有编写指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。

关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、“MAY”和“OPTIONAL”应按照 [RFC2119][RFC8174] 中的描述进行解释,当且仅当它们全部以大写形式出现时,如此处所示。

本规范定义了一致性标准,该标准适用于单个产品:实现其中包含的接口的用户代理。

以算法或特定步骤表达的一致性要求可以通过任何方式实现,只要最终结果是等效的。(特别是,本规范中定义的算法旨在易于理解,而不是为了高性能。)

使用 ECMAScript 实现本规范中定义的 API 的实现必须以符合 Web IDL 规范 [WEBIDL] 中定义的 ECMAScript 绑定的方式实现它们,因为本规范使用了该规范及其术语。

3. 协议概念

WebTransport 有两个主要的协议概念:会话和流。每个 WebTransport 会话 可以包含多个 WebTransport 流

这些不应与 协议名称 混淆,后者是应用层 API 构造。

3.1. WebTransport 会话

一个 WebTransport 会话 是指通过 HTTP/3 或 HTTP/2 底层连接建立的 WebTransport 会话。启用连接池时,一个连接上可能存在多个 WebTransport 会话

根据 [WEB-TRANSPORT-OVERVIEW] 的定义,一个 WebTransport 会话具有以下能力:

能力 定义
发送数据报 [WEB-TRANSPORT-OVERVIEW] 第4.2节
接收数据报 [WEB-TRANSPORT-OVERVIEW] 第4.2节
创建出站单向 [WEB-TRANSPORT-OVERVIEW] 第4.3节
创建双向 [WEB-TRANSPORT-OVERVIEW] 第4.3节
接收入站单向 [WEB-TRANSPORT-OVERVIEW] 第4.3节
接收双向 [WEB-TRANSPORT-OVERVIEW] 第4.3节

WebTransport 会话 session 处于排空状态时,表示CONNECT 流 已由服务器请求优雅关闭,如 [WEB-TRANSPORT-OVERVIEW] 第4.1节所述。

要使用可选的整数code和可选的字节序列reason终止 WebTransport 会话 session,请遵循 [WEB-TRANSPORT-OVERVIEW] 第4.1节

CONNECT 流被服务器关闭时,WebTransport 会话 session终止(可选择 一个整数code字节序列reason) 如 [WEB-TRANSPORT-OVERVIEW] 第4.1节所述。

3.2. WebTransport 流

WebTransport 流是用于 WebTransport 会话 上可靠有序字节流的一个概念,详见 [WEB-TRANSPORT-OVERVIEW] 第4.3节

WebTransport 流分为入站单向出站单向双向

上传输的数据 会作为未分类的字节序列进行传递。 发送端的单次写入操作的字节数,可能与 接收端单次读取操作的字节数不一致。 多次独立的写入可被合并为一个字节序列交付; 一次写入也可能被分开发送。

这包括原子写入, 原子写入的目的在于避免流控死锁, 而不是保证数据同时被传递。

依赖基于消息协议,且需要在发送端与接收端之间 保持消息边界的应用,需要添加帧封装层来 便于重组成消息。

一个WebTransport 流具有以下能力:

能力 定义 入站单向 出站单向 双向
发送 字节(可能带 FIN) [WEB-TRANSPORT-OVERVIEW] 第 4.3 节
接收 字节(可能带 FIN) [WEB-TRANSPORT-OVERVIEW] 第 4.3 节
中止接收WebTransport 流[WEB-TRANSPORT-OVERVIEW] 第 4.3 节
中止发送WebTransport 流[WEB-TRANSPORT-OVERVIEW] 第 4.3 节

一个WebTransport 流具有以下信号:

事件 定义 入站单向 出站单向 双向
接收已中止 [WEB-TRANSPORT-OVERVIEW] 第 4.3 节
发送已中止 [WEB-TRANSPORT-OVERVIEW] 第 4.3 节
流控 [WEB-TRANSPORT-OVERVIEW] 第 4.3 节

4. WebTransportDatagramsWritable 接口

WebTransportDatagramsWritable 是一个 WritableStream,为发送数据报提供出站流式传输功能。

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportDatagramsWritable : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
};

4.1. 内部插槽

一个 WebTransportDatagramsWritable 对象具有以下内部插槽。

内部槽位 描述(非规范性
[[OutgoingDatagramsQueue]] 一个包含外发数据报、时间戳和 promise 的队列,该 promise 会在数据报被发送或丢弃时被解决。
[[Transport]] WebTransport 拥有的这个 WebTransportDatagramsWritable
[[SendGroup]] 可选的 WebTransportSendGroup, 或 null。
[[SendOrder]] 可选的发送顺序号,默认为 0。
创建一个 WebTransportDatagramsWritable, 给定一个 WebTransport transportsendGroupsendOrder,执行以下步骤。
  1. stream 为一个 WebTransportDatagramsWritable, 其各项为:

    [[OutgoingDatagramsQueue]]

    一个空队列

    [[Transport]]

    transport

    [[SendGroup]]

    sendGroup

    [[SendOrder]]

    sendOrder

  2. writeDatagramsAlgorithm 为执行 writeDatagrams, 参数为 transportstream 的操作。

  3. 设置 streamwriteAlgorithm 设置为 writeDatagramsAlgorithm

  4. 返回 stream

4.2. 属性

sendGroup, 类型为 WebTransportSendGroup, 可空

getter 步骤:

  1. 返回 this[[SendGroup]]

setter 步骤,给定 value

  1. 如果 value 非空,且 value.[[Transport]] 不是 this.[[Transport]]抛出一个 InvalidStateError

  2. 设置 this.[[SendGroup]]value

sendOrder, 类型为 long long

getter 步骤:

  1. 返回 this[[SendOrder]]

setter 步骤,给定 value

  1. 设置 this.[[SendOrder]]value

4.3. 过程

writeDatagrams 算法给定一个 transportwritable 作为参数,以及 data 作为输入。它通过运行以下步骤来定义:

  1. timestamp 为一个表示当前时间的 timestamp。

  2. 如果 data 不是 BufferSource 对象,则返回一个被拒绝并附带一个 TypeError 的 promise。

  3. datagramstransport.[[Datagrams]]

  4. 如果 datagrams.[[OutgoingMaxDatagramSize]] 小于 data 的 [[ByteLength]],则返回 一个 promise 被解析,并返回 undefined。

  5. promise 为一个新的 promise。

  6. bytesdata 表示的字节的副本。

  7. chunk 为一个元组,包含 bytestimestamppromise

  8. chunk 入队到 writable.[[OutgoingDatagramsQueue]]

  9. 如果 writable.[[OutgoingDatagramsQueue]] 的长度小于 datagrams.[[OutgoingMaxBufferedDatagrams]],则解析 promise 并返回 undefined。

  10. 返回 promise

注意: 关联的 WritableStream 仅当该流的 writeDatagrams 返回的所有 promise 都已解析时,才会调用 writeDatagrams。因此,只有当 Web 开发人员关注 WritableStreamDefaultWriter.ready 时,时间戳和过期持续时间才能很好地工作。

sendDatagrams,给定一个 WebTransport 对象 transport 和一个 WebTransportDatagramsWritable 对象 writable将一个网络任务入队,使用 transport 运行以下步骤:

  1. queuewritable.[[OutgoingDatagramsQueue]] 的副本。

    注意: 上述副本以及将网络任务排队以运行这些步骤都可以进行优化。

  2. maxSizetransport.[[Datagrams]].[[OutgoingMaxDatagramSize]]

  3. durationtransport.[[Datagrams]].[[OutgoingDatagramsExpirationDuration]]

  4. 如果 duration 为 null,则将 duration 设置为一个 实现定义的值。

  5. 并行运行以下步骤:

    1. queue 不为空时:

      1. bytestimestamppromisequeue 的第一个元素。

      2. 如果自 timestamp 以来经过的时间超过 duration 毫秒,则:

        1. queue 中移除第一个元素。

        2. 将一个网络任务入队,使用 transport 解析 promise 并返回 undefined。

      3. 否则,跳出此循环。

    2. 如果 transport.[[State]] 不是 "connected",则返回。

    3. queue 不为空时:

      1. bytestimestamppromisequeue 的第一个元素。

      2. 如果 bytes 的长度 ≤ maxSize

        1. 如果无法立即将 bytes 发送到网络,则跳出此循环。

        2. 发送一个数据报,使用 transport.[[Session]]bytes

      3. queue 中移除第一个元素。

      4. 将一个网络任务入队,使用 transport 解析 promise 并返回 undefined。

用户代理必须针对任何 WebTransport 对象, 只要其 [[State]]"connecting""connected", 就应按照 发送顺序规则,对其相关联的部分 WebTransportDatagramsWritable 对象执行 sendDatagrams, 并且只要算法能取得进展,应尽快这么做。

注: 当传输的 [[State]]"connecting" 时允许写入数据报。 这些数据报会被存储在 [[OutgoingDatagramsQueue]], 并且可以和 "connected" 状态下一样被丢弃。 一旦传输的 [[State]] 变为 "connected",就会开始发送队列中的数据报。

发送顺序规则 指的是,整体发送操作可以与之前排队的流和数据报的发送交错进行, 也可以和还未排队但即将通过本传输发送的流和数据报交错进行, 但前提是,只有当所有具有同一 [[SendGroup]] 且更高 [[SendOrder]] ,并且既未出错,也未被流控阻塞的字节全部发送后, 当前发送操作才能继续。

注: 默认的 null sendGroup 也是有效的 sendGroup。

5. WebTransportDatagramDuplexStream 接口

一个 WebTransportDatagramDuplexStream 是一个通用的双工流。

[Exposed=(Window,Worker), SecureContext]
interface WebTransportDatagramDuplexStream {
  WebTransportDatagramsWritable createWritable(
      optional WebTransportSendOptions options = {});
  readonly attribute ReadableStream readable;

  readonly attribute unsigned long maxDatagramSize;
  attribute unrestricted double? incomingMaxAge;
  attribute unrestricted double? outgoingMaxAge;
  attribute unsigned long incomingMaxBufferedDatagrams;
  attribute unsigned long outgoingMaxBufferedDatagrams;
};

5.1. 内部插槽

内部槽 描述(非规范性
[[Transport]] 拥有此 WebTransportWebTransportDatagramDuplexStream
[[Readable]] 用于接收数据报的 ReadableStream
[[ReadableType]] 用于接收数据报的 ReadableStreamType
[[Writables]] 一个有序集合WebTransportDatagramsWritable 流,初始为空。
[[IncomingDatagramsQueue]] 一个队列,包含每个接收数据报和其时间戳的对。
[[IncomingDatagramsPullPromise]] 通过 pullDatagrams 设置的一个 promise,用于等待接收数据报。
[[IncomingMaxBufferedDatagrams]] 一个 unsigned long, 用于表示接收队列的长度(以数据报数量计),超出后队首的数据报会被丢弃。
[[IncomingDatagramsExpirationDuration]] 一个 unrestricted double, 表示接收数据报的过期时长(毫秒),或为 null。
[[OutgoingMaxBufferedDatagrams]] 一个 unsigned long, 表示底层 sink 的发送队列长度(以数据报数量计),超出后将产生背压。
[[OutgoingDatagramsExpirationDuration]] 一个 unrestricted double ,表示发送数据报的过期时长(毫秒),或为 null。
[[OutgoingMaxDatagramSize]] 一个整数,表示单个发送数据报的最大尺寸。
最大数据报大小取决于所用协议。 在 HTTP/3 [WEB-TRANSPORT-HTTP3] 中,该值与路径 MTU 的估算有关, 并会因实现定义的开销而减小。 在 HTTP/2 [WEB-TRANSPORT-HTTP2] 中没有类似限制。

由于处理数据报时通常需要在内存中暂存整个数据报, 实现会有限制其大小的机制。 将来协议扩展可能支持全部协议变体下大小限制的信号。

用户代理可以随时更新任何 [[OutgoingMaxDatagramSize]] ,只要对应的 WebTransport 对象其 [[State]]"connecting""connected"

创建 一个 WebTransportDatagramDuplexStream ,给定 WebTransport transportreadablereadableType,执行以下步骤:
  1. stream 是一个 新建 WebTransportDatagramDuplexStream,其属性:

    [[Transport]]

    transport

    [[Readable]]

    readable

    [[ReadableType]]

    readableType

    [[Writables]]

    一个空的 有序集合

    [[IncomingDatagramsQueue]]

    一个空队列

    [[IncomingDatagramsPullPromise]]

    null

    [[IncomingMaxBufferedDatagrams]]

    一个由实现定义的值

    [[IncomingDatagramsExpirationDuration]]

    null

    [[OutgoingMaxBufferedDatagrams]]

    一个由实现定义的值

    此实现定义的值应调优以保证传输吞吐量合理,同时不影响传输数据的时效性。

    [[OutgoingDatagramsExpirationDuration]]

    null

    [[OutgoingMaxDatagramSize]]

    一个由实现定义的整数。

  2. 返回 stream

5.2. 方法

createWritable(options)

创建一个 WebTransportDatagramsWritable。 在被调用时,用户代理必须 运行以下步骤:

  1. transport 为与 this 关联的 WebTransport 对象。

  2. sendGroupoptionssendGroup

  3. 如果 sendGroup 不为 null,且 sendGroup.[[Transport]] 不是 this.[[Transport]], 则抛出 一个 TypeError

  4. 如果 transport.[[State]]"closed""failed", 则抛出 一个 InvalidStateError

  5. sendOrderoptionssendOrder

  6. 返回以 transportsendGroupsendOrder 创建一个 WebTransportDatagramsWritable 的结果。

5.3. 属性

readable 类型为 ReadableStream,只读

getter 步骤如下:

  1. 返回 this.[[Readable]]

incomingMaxAge 类型为 unrestricted double,可为 null

getter 步骤如下:

  1. 返回 this.[[IncomingDatagramsExpirationDuration]]

setter 步骤,给定 value

  1. 如果 value 为负数或 NaN,则抛出一个 RangeError

  2. 如果 value0,将 value 设为 null。

  3. this.[[IncomingDatagramsExpirationDuration]] 设为 value

maxDatagramSize 类型为 unsigned long,只读

可传递至 WebTransportDatagramsWritable 的数据的最大字节数。 getter 步骤是返回 this.[[OutgoingMaxDatagramSize]]

outgoingMaxAge 类型为 unrestricted double,可为 null

getter 步骤如下:

  1. 返回 this[[OutgoingDatagramsExpirationDuration]]

setter 步骤,给定 value

  1. 如果 value 为负数或 NaN,则抛出一个 RangeError

  2. 如果 value0,将 value 设为 null。

  3. this.[[OutgoingDatagramsExpirationDuration]] 设为 value

incomingMaxBufferedDatagrams 类型为 unsigned long

getter 步骤如下:

  1. 返回 this.[[IncomingMaxBufferedDatagrams]]

setter 步骤,给定 value

  1. 如果 value 小于 1,将 value 设为 1

  2. this.[[IncomingMaxBufferedDatagrams]] 设为 value

outgoingMaxBufferedDatagrams 类型为 unsigned long

getter 步骤如下:

  1. 返回 this.[[OutgoingMaxBufferedDatagrams]]

setter 步骤,给定 value

  1. 如果 value 小于 1,将 value 设为 1

  2. this.[[OutgoingMaxBufferedDatagrams]] 设为 value

5.4. 过程

拉取数据报,给定 WebTransport 对象 transport,执行以下步骤:

  1. datagramstransport.[[Datagrams]]

  2. 断言:datagrams.[[IncomingDatagramsPullPromise]] 为 null。

  3. queuedatagrams.[[IncomingDatagramsQueue]]

  4. 如果 queue 为空,则:

    1. datagrams.[[IncomingDatagramsPullPromise]] 设为新的 promise。

    2. 返回 datagrams.[[IncomingDatagramsPullPromise]]

  5. datagramtimestamp出队 queue 的结果。

  6. 如果 datagrams.[[ReadableType]]"bytes",则:

    1. datagrams.[[Readable]]現在の BYOB リクエストビュー が null でない場合、次を実行する:

      1. viewdatagrams.[[Readable]]現在の BYOB リクエスト ビュー とする。

      2. viewバイト長datagram のサイズより小さい場合、 RangeError却下された promiseを返す。

      3. elementSize を、view.[[TypedArrayName]] について 型付き配列コンストラクター表 で指定される要素サイズとする。 view に [[TypedArrayName]] 内部スロットがない場合 (すなわち、それが DataView である場合)、 elementSize を 0 とする。

      4. elementSize が 1 でない場合、TypeError却下された promiseを返す。

    2. バイトからプルして、datagramdatagrams.[[Readable]] に取り込む。

  7. 否则:

    1. chunk 为一个新的 Uint8Array 对象,表示 datagram

    2. 入队 chunktransport.[[Datagrams]].[[Readable]]

  8. 返回 一个已解决的 promise,值为 undefined。

接收数据报, 给定 WebTransport 对象 transport,按以下步骤执行:

  1. timestamp 为当前时间的时间戳。

  2. queue 等于 datagrams.[[IncomingDatagramsQueue]]

  3. duration 等于 datagrams.[[IncomingDatagramsExpirationDuration]]

  4. 如果 duration 为 null,则将 duration 设置为一个 由实现定义的值。

  5. session 等于 transport.[[Session]]

  6. 只要 session 上有 可用传入数据报

    1. datagram 等于 接收数据报的结果, 参数为 session

    2. timestamp 为当前时间的时间戳。

    3. chunkdatagramtimestamp 的对。

    4. 入队 chunkqueue

  7. toBeRemovedqueue 的长度减去 datagrams.[[IncomingMaxBufferedDatagrams]]

  8. 如果 toBeRemoved 为正,则重复 出队 queue toBeRemoved向下取整)次。

  9. 只要 queue 非空:

    1. bytestimestampqueue 的第一个元素。

    2. 如果 timestamp 距现在已过去超过 duration 毫秒,则 出队 queue

    3. 否则,跳出此循环。

  10. 如果 queue 非空且 datagrams.[[IncomingDatagramsPullPromise]] 非 null,则:

    1. bytestimestamp 等于 出队 queue 的结果。

    2. promise 等于 datagrams.[[IncomingDatagramsPullPromise]]

    3. 设置 datagrams.[[IncomingDatagramsPullPromise]] 为 null。

    4. 队列一个网络任务, 参数为 transport,任务内容如下:

      1. chunk 为表示 bytes 的新 Uint8Array 对象。

      2. 入队 chunkdatagrams.[[Readable]]

      3. 解决 promise,值为 undefined。

只要算法能取得进展,用户代理应尽快为任何 WebTransport 对象 (其 [[State]]"connected") 运行 接收数据报

6. WebTransport 接口

WebTransport 提供了一个 API,用于访问 [WEB-TRANSPORT-OVERVIEW] 中定义的底层传输功能。

[Exposed=(Window,Worker), SecureContext]
interface WebTransport {
  constructor(USVString url, optional WebTransportOptions options = {});

  Promise<WebTransportConnectionStats> getStats();
  [NewObject] Promise<Uint8Array> exportKeyingMaterial(BufferSource label, BufferSource context, unsigned long outputLength);
  readonly attribute Promise<undefined> ready;
  readonly attribute WebTransportReliabilityMode reliability;
  readonly attribute WebTransportCongestionControl congestionControl;
  attribute [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams;
  attribute [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams;
  [SameObject] readonly attribute Headers? responseHeaders;
  readonly attribute DOMString protocol;

  readonly attribute Promise<WebTransportCloseInfo> closed;
  readonly attribute Promise<undefined> draining;
  undefined close(optional WebTransportCloseInfo closeInfo = {});

  readonly attribute WebTransportDatagramDuplexStream datagrams;

  Promise<WebTransportBidirectionalStream> createBidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportBidirectionalStream objects */
  readonly attribute ReadableStream incomingBidirectionalStreams;

  Promise<WebTransportSendStream> createUnidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportReceiveStream objects */
  readonly attribute ReadableStream incomingUnidirectionalStreams;
  WebTransportSendGroup createSendGroup();

  static readonly attribute boolean supportsReliableOnly;
};

enum WebTransportReliabilityMode {
  "pending",
  "reliable-only",
  "supports-unreliable",
};

6.1. 内部插槽

一个 WebTransport 对象具有以下内部槽位。

内部槽 描述(非规范性
[[SendStreams]] 一个 有序集合, 由本 WebTransportSendStream 拥有。
[[ReceiveStreams]] 一个 有序集合, 由本 WebTransportReceiveStream 拥有。
[[IncomingBidirectionalStreams]] 一个 ReadableStream ,由 WebTransportBidirectionalStream 对象组成。
[[IncomingUnidirectionalStreams]] 一个 ReadableStream ,由 WebTransportReceiveStream 组成。
[[State]] 用于指示传输状态的枚举值,可能为 "connecting""connected""draining""closed""failed" 之一。
[[Ready]] 在相关 WebTransport 会话 建立 后 fulfill, 如果 建立过程失败则 reject。
[[Reliability]] 一个 WebTransportReliabilityMode ,指示首跳是否支持不可靠(UDP)传输或仅支持可靠(TCP)传输。连接建立前返回 "pending"
[[CongestionControl]] 一个 WebTransportCongestionControl ,用于指示应用是否请求并被用户代理满足了优化吞吐量或低延迟的拥塞控制算法,或 "default"
[[AnticipatedConcurrentIncomingUnidirectionalStreams]] 应用预期服务器创建的并发打开的 入向单向流数量,或为 null。
[[AnticipatedConcurrentIncomingBidirectionalStreams]] 应用预期服务器创建的并发打开的 双向流数量,或为 null。
[[ResponseHeaders]] 一个 Headers 对象或 null。初始值为 null。
[[Protocol]] 一个字符串,指示服务器选择的应用层协议(如有)。初始值为空字符串。
[[Closed]] 在相关 WebTransport 对象 正常关闭时 fulfill,异常或初始化失败时 reject。
[[Draining]] 在相关 WebTransport 会话 开始 draining 时 fulfill。
[[Datagrams]] 一个 WebTransportDatagramDuplexStream
[[Session]] 用于此 WebTransport 对象的 WebTransport 会话,或 null。
[[NewConnection]] "no" 或 "yes-and-dedicated"。
[[RequireUnreliable]] 一个布尔值,表示是否需要 UDP。

6.2. 构造函数

当调用 WebTransport() 构造器时,用户 代理必须运行以下步骤:
  1. baseURLthis相关设置对象API 基准 URL

  2. url 为使用 baseURL解析 url 所得到的 URL 记录

  3. 如果 url 为 failure,则抛出一个 SyntaxError 异常。

  4. 如果 url方案不是 https,则抛出一个 SyntaxError 异常。

  5. 如果 url片段不为 null,则抛出一个 SyntaxError 异常。

  6. 如果 optionsallowPooling 为 true,则令 newConnection 为“no”;否则为“yes-and-dedicated”。

  7. serverCertificateHashesoptionsserverCertificateHashes

  8. 如果 newConnection 为“no”且 serverCertificateHashes 非空,则抛出一个 NotSupportedError 异常。

  9. requireUnreliableoptionsrequireUnreliable

  10. congestionControloptionscongestionControl

  11. 如果 congestionControl 不是 "default",并且用户代理不支持任何 按照 [RFC9002] 第 7 节 所允许的、针对 congestionControl 优化的拥塞控制算法, 则将 congestionControl 设为 "default"

  12. protocolsoptionsprotocols

  13. 如果 protocols 中的任意值出现多于一次,未能匹配 WebTransport 协议所定义的、组成协商后 应用协议值的元素要求,或者其同构编码 长度为 0 或超过 512,则抛出一个 SyntaxError 异常。 [WEB-TRANSPORT-OVERVIEW] 第 3.1 节

  14. anticipatedConcurrentIncomingUnidirectionalStreamsoptionsanticipatedConcurrentIncomingUnidirectionalStreams

  15. anticipatedConcurrentIncomingBidirectionalStreamsoptionsanticipatedConcurrentIncomingBidirectionalStreams

  16. datagramsReadableTypeoptionsdatagramsReadableType

  17. incomingDatagrams 为一个新的 ReadableStream

  18. transport 为一个新构造的 WebTransport 对象,其包含:

    [[SendStreams]]

    一个空有序集合

    [[ReceiveStreams]]

    一个空有序集合

    [[IncomingBidirectionalStreams]]

    一个新的 ReadableStream

    [[IncomingUnidirectionalStreams]]

    一个新的 ReadableStream

    [[State]]

    "connecting"

    [[Ready]]

    一个新的 promise

    [[Reliability]]

    "pending"

    [[CongestionControl]]

    congestionControl

    [[AnticipatedConcurrentIncomingUnidirectionalStreams]]

    anticipatedConcurrentIncomingUnidirectionalStreams

    [[AnticipatedConcurrentIncomingBidirectionalStreams]]

    anticipatedConcurrentIncomingBidirectionalStreams

    [[ResponseHeaders]]

    null

    [[Protocol]]

    空字符串

    [[Closed]]

    一个新的 promise

    [[Draining]]

    一个新的 promise

    [[Datagrams]]

    undefined

    [[Session]]

    null

    [[NewConnection]]

    newConnection

    [[RequireUnreliable]]

    requireUnreliable

  19. transport.[[Datagrams]] 设为用 transportincomingDatagramsdatagramsReadableType创建 一个 WebTransportDatagramDuplexStream 的结果。

  20. pullDatagramsAlgorithm 为一个运行带有 transportpullDatagrams 的动作。

    注: 建议对 数据报使用 64 kibibytes 的缓冲区,因为有效的 最大 WebTransport 数据报帧大小存在一个由 QUIC 最大数据报帧 大小给出的上界, 而该大小建议为 64 kibibytes(见 [QUIC-DATAGRAM] 第 3 节)。 这将确保流不会因数据报大于缓冲区而出错。

  21. 如果 datagramsReadableType"bytes",则用pullAlgorithm 设为 pullDatagramsAlgorithm、且 highWaterMark 设为 0 来对 incomingDatagrams设置字节读取 支持。否则,用 pullAlgorithm 设为 pullDatagramsAlgorithm,并且 highWaterMark 设为 0 来设置 incomingDatagrams

  22. pullBidirectionalStreamAlgorithm 为一个运行带有 transportpullBidirectionalStream 的动作。

  23. pullAlgorithm 设为 pullBidirectionalStreamAlgorithm,并且 highWaterMark 设为 0 来设置 transport.[[IncomingBidirectionalStreams]]

  24. pullUnidirectionalStreamAlgorithm 为一个运行带有 transportpullUnidirectionalStream 的动作。

  25. pullAlgorithm 设为 pullUnidirectionalStreamAlgorithm,并且 highWaterMark 设为 0 来设置 transport.[[IncomingUnidirectionalStreams]]

  26. clienttransport相关设置对象

  27. originclient

  28. request 为一个新的请求,其URLurlclientclientservice-workers mode 为“none”, referrer 为“no-referrer”,mode 为“webtransport”, credentials mode 为“omit”, cache mode 为“no-store”, policy containerclientpolicy containerdestination 为 "", originoriginWebTransport-hash listserverCertificateHashes,且redirect mode 为 "error"。

    注: 重定向不会被跟随。由重定向导致的网络 错误有意与其他网络错误 无法区分。在跨源上下文中,这会泄露 通常会被 CORS 阻止的信息。在同源上下文中,它可能 鼓励应用滥用握手,将其作为传递信息的向量。

  29. request方法设为“CONNECT”,并将该 方法关联的 :protocol 伪首部设为 "webtransport"

  30. headers 为一个新的 Headers 对象,并用 options["headers"] 填充

  31. requestHeaders 为一个新的 Headers 对象,其首部列表request首部列表,且保护为“request”。

  32. 对于 headers首部列表中的每个 header

    1. 如果 header名称ASCII 小写化后为“wt-available-protocols”, 则抛出一个 TypeError

    2. header附加requestHeaders

    注: 首部受 Fetch 的 被禁止的请求首部 限制约束。

  33. 如果 protocols 非空,则在 request首部列表中,用 (WT-Available-Protocols,一个 结构化首部列表,其成员为按顺序取自 protocols 结构化首部字符串项)设置结构化字段值

  34. Fetch request,其中 useParallelQueue 设为 true,且 processResponse 设为以下给定 response 的步骤:

    1. responsetransport处理 WebTransport fetch 响应

  35. 返回 transport

获取一个 WebTransport 连接,给定一个 网络 分区键 networkPartitionKey,以及一个 请求 request
  1. transport 为与 request 关联的 WebTransport 对象。

  2. urlrequest当前 URL

  3. newConnectiontransport.[[NewConnection]]

  4. requireUnreliabletransport.[[RequireUnreliable]]

  5. webTransportHashesrequestWebTransport-hash 列表中的值。

  6. connection 为使用 networkPartitionKeyurl、false、newConnectionrequireUnreliablewebTransportHashes获取连接的结果。

  7. 如果 connection 为 failure,则返回 failure。

  8. 等待 connection 接收第一个 SETTINGS 帧,并令 settings 为表示该 SETTINGS 帧的字典。

  9. 如果 settings 不包含值为 1 的 SETTINGS_ENABLE_CONNECT_PROTOCOL(0x08,对于 HTTP/2,见 第 3 节,见 [RFC8441]; 0x08,见 第 3 节 of [RFC9220]),则返回 failure。

  10. 如果 settings 未指示服务器支持 WebTransport,则返回 failure。 [WEB-TRANSPORT-OVERVIEW] 第 4.1 节

  11. 返回 connection

处理一个 WebTransport fetch 响应,给定一个 response response 和一个 WebTransport transport,运行以下步骤:
  1. 如果 response网络错误,则中止剩余步骤并对 transport 排列一个网络任务以运行下列步骤:

    1. 如果 transport[[State]]"closed""failed",则中止这些步骤。

    2. error 为新创建的一个 WebTransportError,其 source"session"

    3. transport 执行 Cleanup,参数为 error

  2. connection 为与 response 关联的底层连接。

  3. 遵循 [WEB-TRANSPORT-OVERVIEW] Section 4.1 中的任何限制,在 connection建立 一个 WebTransport 会话,使用服务器的 response, 并令 session 为所得的 WebTransport 会话。 由此产生的底层传输流称为该会话的 CONNECT 流

    注: 此步骤也完成了在 [QUIC-DATAGRAM] 中指定的传输参数交换。

  4. 如果前一步失败,则中止剩余步骤并对 transport 排列一个网络任务以运行下列步骤:

    1. 如果 transport[[State]]"closed""failed",则中止这些步骤。

    2. error 为新创建的一个 WebTransportError,其 source"session"

    3. transport 执行 Cleanup,参数为 error

  5. 如果用户代理支持多个拥塞控制算法,则为此 connection 上的数据发送选择一个适合 transport[[CongestionControl]]

  6. transport 排列一个网络任务以运行下列步骤:

    1. 断言:this[[Datagrams]][[OutgoingMaxDatagramSize]] 为整数。

    2. 如果 transport[[State]] 不是 "connecting"

      1. 并行地,对 session 执行 terminate

      2. 中止这些步骤。

    3. transport[[State]] 设为 "connected"

    4. transport[[Session]] 设为 session

    5. responseHeadersresponseheader list 的副本。

    6. responseHeaders删除 "wt-protocol"。

    7. transport[[ResponseHeaders]] 设为一个新的 Headers 对象, 其 header listresponseHeaders,且 guard 为 "immutable"。

    8. transport[[Protocol]] 设为协商出的应用层协议的字符串值(如果存在),遵循 [WEB-TRANSPORT-OVERVIEW] Section 3.1,若不存在则设为 ""

    9. 如果连接为 HTTP/3 连接,则将 transport[[Reliability]] 设为 "supports-unreliable"

    10. 如果连接为 HTTP/2 连接 [WEB-TRANSPORT-HTTP2],则将 transport[[Reliability]] 设为 "reliable-only"

    11. Resolve transport[[Ready]] 为 undefined。

pullBidirectionalStream,给定一个 WebTransport 对象 transport,运行下列步骤。
  1. 如果 transport[[State]]"connecting",则在 transport[[Ready]] 被满足后,返回执行下列步骤的结果:

    1. transport 为参数再次调用并返回 pullBidirectionalStream 的结果。

  2. 如果 transport[[State]] 不是 "connected",则返回一个新的被拒绝的 promise,原因是一个 InvalidStateError

  3. sessiontransport[[Session]]

  4. p 为一个新的 promise。

  5. 并行运行下列步骤:

    1. 等待直到 session 中有一个 可用的入向双向流

    2. internalStream 为从 session 接收一个双向流 的结果。

    3. transport 排列一个网络任务以运行下列步骤:

      1. stream 为使用 internalStreamtransport 创建的 WebTransportBidirectionalStream 对象的结果。

      2. stream 入队到 transport[[IncomingBidirectionalStreams]]

      3. Resolve p,值为 undefined。

  6. 返回 p

pullUnidirectionalStream,给定一个 WebTransport 对象 transport,运行以下步骤。
  1. 如果 transport[[State]]"connecting",则在 transport[[Ready]] 被满足后返回执行下列步骤的结果:

    1. transport 为参数再次调用并返回 pullUnidirectionalStream 的结果。

  2. 如果 transport[[State]] 不是 "connected",则返回一个新的被拒绝的 promise,原因为 InvalidStateError

  3. sessiontransport[[Session]]

  4. p 为一个新的 promise。

  5. 并行运行下列步骤:

    1. 等待直到 session 中有一个 可用的入向单向流

    2. internalStream 为从 session 接收一个入向单向流 的结果。

    3. transport 排列一个网络任务以运行下列步骤:

      1. stream 为使用 internalStreamtransport 创建的 WebTransportReceiveStream 的结果。

      2. stream 入队到 transport[[IncomingUnidirectionalStreams]]

      3. Resolve p,值为 undefined。

  6. 返回 p

6.3. 属性

ready类型为 Promise<undefined>,只读

读取时,必须返回 this[[Ready]]

closed类型为 Promise<WebTransportCloseInfo>,只读

读取时,必须返回 this[[Closed]]

draining类型为 Promise<undefined>,只读

读取时,必须返回 this[[Draining]]

datagrams类型为 WebTransportDatagramDuplexStream, 只读

用于在本会话中收发数据报的单个双工流。 datagrams 属性的 getter 步骤如下:

  1. 返回 this[[Datagrams]]

incomingBidirectionalStreams类型为 ReadableStream,只读

返回由服务器接收的 ReadableStream ,其元素为 WebTransportBidirectionalStream

注:传入流是否已有数据,取决于服务器行为。

incomingBidirectionalStreams 属性的 getter 步骤如下:

  1. 返回 this[[IncomingBidirectionalStreams]]

incomingUnidirectionalStreams类型为 ReadableStream,只读

一个单向流的 ReadableStream, 每个流由一个 WebTransportReceiveStream 表示, 它们都来自服务器。

注:传入流是否已有数据,取决于服务器行为。

incomingUnidirectionalStreams 的 getter 步骤如下:

  1. 返回 this.[[IncomingUnidirectionalStreams]]

reliability类型为 WebTransportReliabilityMode, 只读

表示连接是否支持不可靠(基于 UDP)传输或只支持可靠(TCP 回退)传输。 在未建立连接前返回 "pending"。 getter 步骤为返回 this[[Reliability]]

congestionControl 类型为 WebTransportCongestionControl, 只读

应用层的偏好,如果在构造函数中指定并被用户代理满足,则该连接发送数据时使用针对吞吐量或低延迟优化的拥塞控制算法。如果请求了偏好但未被满足,则值为 "default"。 getter 步骤为返回 this[[CongestionControl]]

supportsReliableOnly类型为 boolean,只读

当用户代理支持仅通过可靠 WebTransport 会话连接 时返回 true,否则为 false。

anticipatedConcurrentIncomingUnidirectionalStreams类型为 unsigned short,可为 null

允许应用可选地声明其预期服务器将创建的并发 传入单向流的数量。 如果非 null,用户代理在与服务器协商时应尝试将 [[AnticipatedConcurrentIncomingUnidirectionalStreams]] 纳入考虑,从而减少未来往返次数。

getter 步骤为返回 this[[AnticipatedConcurrentIncomingUnidirectionalStreams]]

setter 步骤,给定 value,是将 this[[AnticipatedConcurrentIncomingUnidirectionalStreams]] 设置为 value

anticipatedConcurrentIncomingBidirectionalStreams类型为 unsigned short,可为 null

允许应用可选地声明其预期服务器将创建的并发 双向流的数量。 如果非 null,用户代理在与服务器协商时应尝试将 [[AnticipatedConcurrentIncomingBidirectionalStreams]] 纳入考虑,从而减少未来的往返次数。

getter 步骤为返回 this[[AnticipatedConcurrentIncomingBidirectionalStreams]]

setter 步骤,给定 value,是将 this[[AnticipatedConcurrentIncomingBidirectionalStreams]] 设置为 value

注:设置 anticipatedConcurrentIncomingUnidirectionalStreamsanticipatedConcurrentIncomingBidirectionalStreams 不能保证应用会收到预期数量的流。

responseHeaders, 类型为 Headers,只读,可为 null

一旦建立了 WebTransport 会话, 保存由服务器设置的应用层响应头(如果有)。初始值为 null。 获取器步骤是返回 this[[ResponseHeaders]]

protocol, 类型为 DOMString,只读

一旦建立了 WebTransport 会话 且构造函数选项中的 protocols 提供了非空数组,则返回服务器选择的应用层协议(如果有)。否则返回空字符串。 获取器步骤是返回 this[[Protocol]]

6.4. 方法

close(closeInfo)

终止与 WebTransport 对象关联的 WebTransport 会话。 在被调用时,用户代理必须运行以下步骤:

  1. transportthis

  2. 如果 transport.[[State]]"closed""failed",则中止这些步骤。

  3. 如果 transport.[[State]]"connecting"

    1. error 为一个新创建WebTransportError, 其 source"session"

    2. error 清理 transport

    3. 中止这些步骤。

  4. sessiontransport.[[Session]]

  5. codecloseInfo.closeCode

  6. reasonStringcloseInfo.reason 的最大码元前缀,其中该 UTF-8 编码前缀的 长度不超过 1024。

  7. reason 为经过 UTF-8 编码reasonString

  8. 并行地,用 codereason 终止 session

    注:这也会在 transport.[[SendStreams]][[ReceiveStreams]] 中包含的 WebTransport 流中止发送中止接收

  9. AbortErrorcloseInfo 清理 transport

getStats()

收集此 WebTransport底层连接的统计信息, 并异步报告结果。

在被调用时,用户代理必须运行以下步骤:

  1. transportthis

  2. p 为一个新的 promise。

  3. 如果 transport.[[State]]"failed",则用 InvalidStateError 拒绝 p, 并中止这些步骤。

  4. 并行地运行以下步骤:

    1. 如果 transport.[[State]]"connecting",则等待直到其发生变化。

    2. 如果 transport.[[State]]"failed",则在用 transport 将一个网络任务排队 以用 InvalidStateError 拒绝 p 之后, 中止这些步骤。

    3. 如果 transport.[[State]]"closed",则在用 transport 将一个网络任务排队 以用该连接最近可用的统计信息 兑现 p 之后, 中止这些步骤。这些统计信息被收集的确切时点是实现定义的。

    4. gatheredStats 为准确填充 WebTransportConnectionStatsWebTransportDatagramStats字典成员所需的、 特定于 底层连接的统计信息列表

    5. 如果 transport.[[NewConnection]] 为 "no",则从 gatheredStats 中移除所有未标记为池化连接统计信息的统计信息。

    6. transport 将一个网络任务排队 以运行以下步骤:

      1. stats 为一个新的 WebTransportConnectionStats 对象。

      2. datagramStats 为一个新的 WebTransportDatagramStats 对象。

      3. stats["datagrams"] 设为 datagramStats

      4. 对于用户代理希望公开的 statsdatagramStats 的每个成员 member, 将 member 设置gatheredStats 中对应的条目

      5. stats 兑现 p

  5. 返回 p

exportKeyingMaterial(BufferSource label, BufferSource context, unsigned long outputLength)

从与此 WebTransport底层连接唯一关联的 TLS 会话中, 通过 TLS 密钥材料导出器导出密钥材料。 调用时,用户代理必须运行以下步骤:

  1. labelLengthlabel字节长度

  2. 如果 labelLength 大于 255,则返回一个被拒绝的 promise,拒绝原因为 RangeError

  3. contextLengthcontext字节长度

  4. 如果 contextLength 大于 255,则返回一个被拒绝的 promise,拒绝原因为 RangeError

  5. 如果 outputLength 为 0,或大于某个实现定义的值——该值必须至少为 4096——则返回一个被拒绝的 promise,拒绝原因为 RangeError

  6. 如果 this.[[State]]"closed""failed", 则返回一个被拒绝的 promise,拒绝原因为 InvalidStateError

  7. transportthis

  8. p 为一个新的 promise。

  9. 并行运行以下步骤,但在……时中止 transport[[State]] 变为 "closed""failed",并改为 排入一个网络任务,其关联的 transporttransport,以用 InvalidStateError 拒绝 p

    1. keyingMaterial 为一个 Uint8Array, 它通过调用 TLS 密钥导出器产生,如 [WEB-TRANSPORT-OVERVIEW] 第 4.1 节所定义, 并传入 labelcontextoutputLength

    2. 排入一个网络任务, 其关联的 transporttransport,以用 keyingMaterial 兑现 p

  10. 返回 p

createBidirectionalStream(options)

为传出的双向流创建一个 WebTransportBidirectionalStream 对象。请注意,仅创建一个流不会立即让对等方可见,直到 它被用于发送数据。

注: 不期望 服务器在流上发送数据之前就知道该流。

调用时,用户代理必须运行以下步骤:

  1. sendGroupoptionssendGroup

  2. 如果 sendGroup 不为 null,且 sendGroup.[[Transport]] 不是 this,则返回一个被拒绝的 promise,拒绝原因为 TypeError

  3. 如果 this.[[State]]"closed""failed", 则返回一个被拒绝的 promise,拒绝原因为 InvalidStateError

  4. sendOrderoptionssendOrder

  5. waitUntilAvailableoptionswaitUntilAvailable

  6. p 为一个新的 promise。

  7. transportthis

  8. 并行运行以下步骤,但在……时中止 transport[[State]] 变为 "closed""failed",并改为 排入一个网络任务,其关联的 transporttransport,以用 InvalidStateError 拒绝 p

    1. streamId 为一个新的流 ID,该 ID 对 transport.[[Session]] 有效且唯一,如 [QUIC] 第 19.11 节所定义。如果由于耗尽而无法 立即获得这样的 ID,则如果 waitUntilAvailable 为 true,就等待其变得 可用;或者如果 waitUntilAvailable 为 false, 则在排入一个网络任务之后 中止这些步骤,该任务关联的 transporttransport,以 拒绝 p 并给出一个 QuotaExceededError, 其 requestedquota 均为 null。

    2. internalStream 为使用 transport.[[Session]]streamId 创建双向流的结果。

    3. 排入一个网络任务, 其关联的 transporttransport,以运行以下步骤:

      1. 如果 transport.[[State]]"closed""failed", 则用 InvalidStateError 拒绝 p, 并中止这些步骤。

      2. stream 为使用 internalStreamtransportsendGroupsendOrder 创建一个 WebTransportBidirectionalStream 的结果。

      3. stream 兑现 p

  9. 返回 p

createUnidirectionalStream(options)

为传出的单向流创建一个 WebTransportSendStream。 请注意,仅创建一个流不会立即让服务器可见,直到它被用于 发送数据。

注: 不期望 服务器在流上发送数据之前就知道该流。

调用时,用户代理必须运行以下步骤:

  1. sendGroupoptionssendGroup

  2. 如果 sendGroup 不为 null,且 sendGroup.[[Transport]] 不是 this, 则返回一个被拒绝的 promise,拒绝原因为 TypeError

  3. 如果 this.[[State]]"closed""failed", 则返回一个被拒绝的 promise,拒绝原因为 InvalidStateError

  4. sendOrderoptionssendOrder

  5. waitUntilAvailableoptionswaitUntilAvailable

  6. p 为一个新的 promise。

  7. transportthis

  8. 并行运行以下步骤,但在……时中止 transport[[State]] 变为 "closed""failed",并改为 排入一个网络任务,其关联的 transporttransport,以用 InvalidStateError 拒绝 p

    1. streamId 为一个新的流 ID,该 ID 对 transport.[[Session]] 有效且唯一,如 [QUIC] 第 19.11 节所定义。如果由于耗尽而无法 立即获得这样的 ID,则如果 waitUntilAvailable 为 true,就等待其变得 可用;或者如果 waitUntilAvailable 为 false, 则在排入一个网络任务之后 中止这些步骤,该任务关联的 transporttransport,以 拒绝 p 并给出一个 QuotaExceededError

    2. internalStream 为使用 transport.[[Session]]streamId 创建传出单向流的结果。

    3. 排入一个网络任务, 其关联的 transporttransport,以运行以下步骤:

      1. 如果 transport.[[State]]"closed""failed", 则用 InvalidStateError 拒绝 p, 并中止这些步骤。

      2. stream 为使用 internalStreamtransportsendGroup、 和 sendOrder 创建一个 WebTransportSendStream 的结果。

      3. stream 兑现 p

  9. 返回 p

createSendGroup()

创建一个 WebTransportSendGroup

当调用 createSendGroup() 方法时,用户代理必须 运行以下步骤:
  1. 如果 this.[[State]]"closed""failed", 则抛出一个 InvalidStateError

  2. 返回使用 this 创建一个 WebTransportSendGroup 的结果。

6.5. 过程

要使用 error 以及可选的 closeInfo 清理一个 WebTransport transport,运行以下步骤:
  1. sendStreamstransport.[[SendStreams]] 的副本。

  2. receiveStreamstransport.[[ReceiveStreams]] 的副本。

  3. outgoingDatagramWritablestransport.[[Datagrams]].[[Writables]]

  4. incomingDatagramstransport.[[Datagrams]].[[Readable]]

  5. readytransport.[[Ready]]

  6. closedtransport.[[Closed]]

  7. incomingBidirectionalStreamstransport.[[IncomingBidirectionalStreams]]

  8. incomingUnidirectionalStreamstransport.[[IncomingUnidirectionalStreams]]

  9. transport.[[SendStreams]] 设为一个空集合

  10. transport.[[ReceiveStreams]] 设为一个空集合

  11. transport.[[Datagrams]].[[OutgoingDatagramsQueue]] 设为一个空队列

  12. transport.[[Datagrams]].[[IncomingDatagramsQueue]] 设为一个空队列

  13. 如果给定了 closeInfo,则将 transport.[[State]] 设为 "closed"。 否则,将 transport.[[State]] 设为 "failed"

  14. sendStreams 中的每个 stream 执行 以下步骤:

    1. 如果 stream.[[PendingOperation]] 不为 null,则用 error 拒绝 stream.[[PendingOperation]]

    2. error 使 stream 出错。

  15. receiveStreams 中的每个 stream 执行:用 error 使 stream 出错。

    注:脚本作者可以注入代码,并且该代码会 在 promise 兑现过程中同步运行。因此 从这里开始,不要触碰 transport,因为它可能会被脚本以不可预测的 方式变更。 这也适用于调用此过程的逻辑。

  16. 如果给定了 closeInfo,则:

    1. closeInfo 兑现 closed

    2. 断言:ready敲定

    3. 关闭 incomingBidirectionalStreams

    4. 关闭 incomingUnidirectionalStreams

    5. 对于 outgoingDatagramWritables 中的每个 writable关闭 writable

    6. 关闭 incomingDatagrams

  17. 否则:

    1. error 拒绝 closed

    2. closed.[[PromiseIsHandled]] 设为 true。

    3. error 拒绝 ready

    4. ready.[[PromiseIsHandled]] 设为 true。

    5. error 使 incomingBidirectionalStreams 出错。

    6. error 使 incomingUnidirectionalStreams 出错。

    7. 对于 outgoingDatagramWritables 中的每个 writable,用 error 使 writable 出错。

    8. error 使 incomingDatagrams 出错。

要用一个 WebTransport transport 和一系列步骤 steps 将一个网络任务排队,运行以下步骤:

  1. 网络任务源上,使用 transport相关全局对象将一个全局任务排队,以运行 steps

6.6. 并非由客户端发起的会话终止

每当与 WebTransport transport 关联的 WebTransport 会话 带有可选的 codereasonBytes终止时,运行以下步骤:
  1. transport 将一个网络任务排队,以运行这些步骤:

    1. 如果 transport.[[State]]"closed""failed",则中止这些步骤。

    2. error 为一个新创建WebTransportError, 其 source"session"

    3. closeInfo 为一个新的 WebTransportCloseInfo

    4. 如果给定了 code,则将 closeInfocloseCode 设为 code

    5. 如果给定了 reasonBytes,则将 closeInforeason 设为 reasonBytes UTF-8 解码后的结果。

      注:reasonBytes 没有可用的语言或方向 元数据。 显示该值时,可以使用 首个强方向字符启发式 来确定方向。

    6. errorcloseInfo 清理 transport

每当 WebTransport transport底层连接发生连接错误时, 运行以下步骤:
  1. transport 将一个网络任务排队,以运行这些步骤:

    1. 如果 transport.[[State]]"closed""failed",则中止这些步骤。

    2. error 为一个新创建WebTransportError, 其 source"session"

    3. error 清理 transport

6.7. 上下文清理步骤

本规范将 上下文清理步骤 定义为以下步骤,传入 WebTransport transport

  1. 如果 transport.[[State]]"connected",则:

    1. transport.[[State]] 设为 "failed"

    2. 并行地终止 transport.[[Session]]

    3. transport 将一个网络任务排队,以运行以下步骤:

      1. error 为一个新创建WebTransportError, 其 source"session"

      2. error 清理 transport

  2. 如果 transport.[[State]]"connecting",则将 transport.[[State]] 设为 "failed"

    这也需要在 worker 中完成。参见 #127whatwg/html#6731

6.8. 垃圾回收

一个 WebTransport 对象,如果其 [[State]]"connecting",且 [[IncomingBidirectionalStreams]][[IncomingUnidirectionalStreams]]、 任何 WebTransportReceiveStream[[Datagrams]].[[Readable]]锁定,或者 readydrainingclosed promise 正被观察,则不得被垃圾回收。

一个 WebTransport 对象,如果其 [[State]]"connected",且 [[IncomingBidirectionalStreams]][[IncomingUnidirectionalStreams]]、 任何 WebTransportReceiveStream[[Datagrams]].[[Readable]]锁定,或者 drainingclosed promise 正被观察,则不得被垃圾回收。

一个 WebTransport 对象,如果其 [[State]]"draining",且 [[IncomingBidirectionalStreams]][[IncomingUnidirectionalStreams]]、 任何 WebTransportReceiveStream[[Datagrams]].[[Readable]]锁定,或者 closed promise 正被观察,则不得被垃圾回收。

一个 WebTransport 对象,如果具有一个已建立的 WebTransport 会话, 且有已排队等待传输到网络的数据,包括 [[Datagrams]].[[OutgoingDatagramsQueue]] 中的数据报,则不得被垃圾回收。

如果一个 WebTransport 对象在底层连接 仍处于打开状态时被垃圾回收,则用户代理必须 终止 WebTransport 会话, 并使用应用错误码 0 和应用错误消息 ""

6.9. 配置

dictionary WebTransportHash {
  required DOMString algorithm;
  required BufferSource value;
};

dictionary WebTransportOptions {
  boolean allowPooling = false;
  boolean requireUnreliable = false;
  HeadersInit headers = {};
  sequence<WebTransportHash> serverCertificateHashes = [];
  WebTransportCongestionControl congestionControl = "default";
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams = null;
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams = null;
  sequence<DOMString> protocols = [];
  ReadableStreamType datagramsReadableType;
};

enum WebTransportCongestionControl {
  "default",
  "throughput",
  "low-latency",
};

WebTransportOptions 是一个字典,包含用于控制 WebTransport 会话的建立与使用的参数。

allowPooling, 类型为 boolean,默认值为 false

若设为 true,则 WebTransport 会话允许池化。即其 底层连接 可与其他 WebTransport 会话共享。

requireUnreliable, 类型为 boolean,默认值为 false

若设为 true,则若无法建立 HTTP/3 连接WebTransport 会话不能通过 HTTP/2 连接建立。

headers, 类型为 HeadersInit,默认值为 {}

可选项。可以是 Headers 对象、对象字面量、或二维数组, 用于设置 请求header list,用于 建立 WebTransport 会话时。

serverCertificateHashes, 类型为 sequence<WebTransportHash>,默认值为 []

仅支持专用连接的传输协议。 不支持该功能的传输层,若该字段非空,则必须抛出 NotSupportedError 异常。

若支持且非空,用户代理只在可成功 验证证书哈希serverCertificateHashes 匹配且符合 自定义证书要求时认定证书可信。未知 algorithm 的哈希将被忽略。 若 为空,用户代理采用正常 fetch 流程的证书验证方式。

不可与 allowPooling 一起使用。

congestionControl, 类型为 WebTransportCongestionControl, 默认值为 "default"

可选项,指明应用对拥塞控制算法更偏向吞吐量还是低延迟,发送数据时应采用何种算法。 这是对用户代理的优化建议。

此选项属于风险特性,因为至今浏览器尚无针对低延迟优化的拥塞控制算法实现。

anticipatedConcurrentIncomingUnidirectionalStreams, 类型为 unsigned short,可为 null,默认值为 null

可选项,允许应用指定预期服务器将并发创建多少 入向单向流。 用户代理最初必须允许至少 100 个 入向单向流来自服务器。 若不为 null,用户代理应尝试通过与服务器协商 [[AnticipatedConcurrentIncomingUnidirectionalStreams]] 以减少往返。

anticipatedConcurrentIncomingBidirectionalStreams, 类型为 unsigned short,可为 null,默认值为 null

可选项,允许应用指定预期服务器将并发创建多少 双向流。 用户代理最初必须允许服务器创建至少 100 个 双向流。 若不为 null,用户代理应尝试通过与服务器协商 [[AnticipatedConcurrentIncomingBidirectionalStreams]] 以减少往返。

protocols, 类型为 sequence<DOMString>,默认值为 []

可选,提供一个应用层 协议名称数组。服务器可以选择性地选定优先应用协议并通知客户端。 若未提供合适协议,服务器可能会拒绝请求。

datagramsReadableType, 类型为 ReadableStreamType

可选,指明应用偏好用于接收数据报的 可读字节流。否则使用默认 可读流

注: 虽然 可读流 与数据报语义兼容, 可读字节流则并不兼容。数据报是区分的消息(每个消息为零或多个字节),可以无序到达, 与无分隔的字节序列不同。空的数据报会丢失,且 min 会丢失消息边界。

计算证书哈希,给定 certificate,执行以下步骤:
  1. certcertificate,其表示为 [RFC5280] 中定义的证书消息的 DER 编码。

  2. 计算 cert 的 SHA-256 哈希并返回计算得到的值。

验证证书哈希,给定 certificate chain 和一个哈希数组 hashes,执行以下步骤:
  1. certificatecertificate chain 中的第一个证书(叶子证书)。

  2. referenceHash 为使用 certificate计算证书哈希的结果。

  3. 对于 hashes 中的每个哈希 hash

    1. hash.value 非 null 且 hash.algorithm 与 "sha-256" 为ASCII 不区分大小写匹配:

      1. hashValuehash.value 所表示的字节序列。

      2. hashValue 等于 referenceHash,则返回 true。

  4. 返回 false。

自定义 证书要求如下:证书 必须是 [RFC5280] 中定义的 X.509v3 证书, Subject Public Key 字段中使用的密钥必须是允许的公钥算法之一, 当前时间必须处于证书的有效期内,如 [RFC5280] 第 4.1.2.5 节所定义,并且有效期的总长度 不得超过两周。用户代理可以对证书施加额外的 实现定义要求。

“主体 公钥信息”字段(以及由此导致的 TLS CertificateVerify 消息)中使用的允许的公钥算法的确切列表是由实现定义的;但是,它必须包括使用 secp256r1(NIST P-256)命名组的 ECDSA([RFC3279], 第 2.3.5 节;[RFC9846]), 以提供可互操作的默认选项。它不得包含 RSA 密钥 ([RFC3279], 第 2.3.1 节)。

6.10. WebTransportCloseInfo 字典

WebTransportCloseInfo 字典包含在终止 WebTransport 会话时用于设置错误代码和原因的信息。

dictionary WebTransportCloseInfo {
  unsigned long closeCode = 0;
  USVString reason = "";
};

该字典应具有以下属性:

closeCode类型为 unsigned long,默认为 0

传达给对端的错误代码。

reason类型为 USVString,默认为 ""

关闭 WebTransport 的原因。

6.11. WebTransportSendOptions 字典

WebTransportSendOptions是一个基本参数字典,它会影响 createUnidirectionalStreamcreateBidirectionalStream 以及 createWritable 方法的行为。

dictionary WebTransportSendOptions {
  WebTransportSendGroup? sendGroup = null;
  long long sendOrder = 0;
};

该字典应具有以下属性:

sendGroup, 类型为 WebTransportSendGroup, nullable, 默认为 null

一个可选的 WebTransportSendGroup,用于对创建的流进行分组,或为 null。

sendOrder, 类型为 long long, 默认为 0

一个发送顺序号,如果提供,则选择创建的流参与严格排序。 当前在严格排序的流上排队的字节将优先于当前在其他严格排序的流上排队的字节发送,这些流是使用较低的发送顺序号创建的。

如果未提供发送顺序号,则用户代理从中发送字节的顺序相对于其他流是实现定义的。但是,强烈建议用户代理在所有未被较低发送顺序号饿死的流之间公平地分配带宽。

注意: 这是发送方的数据优先级,不保证接收顺序。

6.12. WebTransportSendStreamOptions 字典

WebTransportSendStreamOptions是一个参数字典,它会影响由 WebTransportSendStream创建的 createUnidirectionalStreamcreateBidirectionalStream的行为。

dictionary WebTransportSendStreamOptions : WebTransportSendOptions {
  boolean waitUntilAvailable = false;
};

该字典应具有以下属性:

waitUntilAvailable类型为 boolean,默认值为 false

如果为 true,则 createUnidirectionalStreamcreateBidirectionalStream 调用返回的 promise 将不会被敲定, 直到底层连接具有足够的流量控制 信用来创建该流,或者该连接达到不可能再创建更多 传出流的状态。如果为 false,则如果在调用时没有可用的流量控制窗口, 该 promise 将被 拒绝

6.13. WebTransportConnectionStats 字典

WebTransportConnectionStats 字典 包含关于 WebTransport 会话底层连接的信息。WebTransportConnectionStats 中未标记为 池化连接 统计项的成员,对于受池化约束的 底层 连接缺失的。

注: 当允许池化时,只会暴露池化 连接统计项, 并且池化在同一连接上的多个 WebTransport 会话都会 接收相同的信息,即该信息会在持有相同 网络分区键的池化会话之间披露。

注: 任何不可用的统计信息都将从 WebTransportConnectionStats 字典中缺失

dictionary WebTransportConnectionStats {
  unsigned long long bytesSent;
  unsigned long long bytesSentOverhead;
  unsigned long long bytesAcknowledged;
  unsigned long long packetsSent;
  unsigned long long bytesLost;
  unsigned long long packetsLost;
  unsigned long long bytesReceived;
  unsigned long long packetsReceived;
  DOMHighResTimeStamp smoothedRtt;
  DOMHighResTimeStamp rttVariation;
  DOMHighResTimeStamp minRtt;
  required WebTransportDatagramStats datagrams;
  unsigned long long? estimatedSendRate = null;
  boolean atSendCapacity = false;
};

该字典应具有以下属性:

bytesSent类型为 unsigned long long

通过底层连接发送的有效载荷字节数,不包括任何成帧 开销或重传。

bytesSentOverhead 类型为 unsigned long long

底层连接上发送 bytesSent 数量的有效载荷字节所产生的成帧和重传开销,以字节为单位。

bytesAcknowledged 类型为 unsigned long long

服务器使用底层连接上的 QUIC ACK 机制确认为已接收的有效载荷字节数。 不包括任何成帧。

注: 通常滞后于 bytesSent, 但由于数据包丢失,可能永久小于它。

bytesAcknowledged 位于 WebTransportConnectionStats 上,由于对可实现性的担忧, 已被工作组标识为一项有风险特性。
packetsSent类型为 unsigned long long

底层连接上发送的数据包数量,包括那些被 判定为已丢失的数据包。

bytesLost类型为 unsigned long long

底层连接上丢失的字节数(不会单调递增, 因为被声明为丢失的数据包随后可能会被接收)。 不包括 UDP 或任何其他外层成帧。

packetsLost类型为 unsigned long long

底层连接上丢失的数据包数量(不会单调递增, 因为被声明为丢失的数据包随后可能会被接收)。

bytesReceived类型为 unsigned long long

底层连接上接收的总字节数,包括 流的重复数据。不包括 UDP 或任何其他外层成帧。

packetsReceived 类型为 unsigned long long

底层连接上接收的总数据包数量,包括 无法处理的数据包。

smoothedRtt类型为 DOMHighResTimeStamp

连接上当前观测到的平滑往返时间(RTT),如 [RFC9002] 第 5.3 节所定义。 这是一个池化连接统计项

rttVariation类型为 DOMHighResTimeStamp

连接上当前观测到的往返时间样本的平均变化量,如 [RFC9002] 第 5.3 节所定义。 这是一个池化连接统计项

minRtt类型为 DOMHighResTimeStamp

在整个连接上观测到的最小往返时间,如 [RFC9002] 第 5.2 节所定义。 这是一个池化连接统计项

estimatedSendRate 类型为 unsigned long long,可为空,默认为 null

用户代理将发送已排队数据的估计速率,以比特每秒为单位。 此速率适用于共享同一个 WebTransport 会话的所有流和数据报, 并由拥塞控制算法计算(该算法可能由 congestionControl选择)。 此估计值不包括任何成帧开销,并 表示应用有效载荷可能被发送的速率。如果用户代理 当前没有估计值,则该成员必须为 null 值。 即使先前结果中它不是 null,该成员也可以为 null。 这是一个池化连接统计项

atSendCapacity 类型为 boolean,默认为 false

false 值表示 estimatedSendRate 可能受应用限制, 意味着应用发送的数据明显少于拥塞 控制器允许的数据量。当拥塞控制器受应用限制时,它可能对 可用网络容量产生较差的估计。

true 值表示应用正以网络 容量发送数据,并且 estimatedSendRate 反映应用可用的网络容量。

atSendCapacitytrue 时,estimatedSendRate 反映一个上限。 只要应用发送速率保持不变,estimatedSendRate 就会适应 网络状况。不过,允许 estimatedSendRateatSendCapacity 为 true 时是 null
这是一个池化连接统计项

6.14. WebTransportDatagramStats 字典

WebTransportDatagramStats 字典包括 有关 底层连接 上数据报传输的统计信息。

dictionary WebTransportDatagramStats {
  unsigned long long droppedIncoming;
  unsigned long long expiredIncoming;
  unsigned long long expiredOutgoing;
  unsigned long long lostOutgoing;
};

该字典应具有以下属性:

droppedIncoming 类型为 unsigned long long

由于应用未从 datagramsreadable 读取数据,新的数据报溢出接收队列前被丢弃的数据报数量。

expiredIncoming 类型为 unsigned long long

由于在被从 datagramsreadable 读取前已超过 incomingMaxAge 而被丢弃的入站数据报数量。

expiredOutgoing 类型为 unsigned long long

排队等待发送的数据报,由于在能够发送前已超过 outgoingMaxAge 而被丢弃的数量。

lostOutgoing 类型为 unsigned long long

已发送的数据报中根据 [RFC9002] 第6.1节 被判定为丢失的数据报数量。

7. 接口 WebTransportSendStream

WebTransportSendStream 是一个 WritableStream ,用于提供出向流特性,可以用于 出向单向双向 WebTransport 流

它是一个 WritableStream ,元素类型为 Uint8Array ,可写入以向服务器发送数据。

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportSendStream : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
  Promise<WebTransportSendStreamStats> getStats();
  WebTransportWriter getWriter();
};

WebTransportSendStream始终由创建过程创建。

WebTransportSendStream传输步骤传输接收步骤那些 WritableStream

7.1. 属性

sendGroup类型为 WebTransportSendGroup,可为 null

getter 步骤如下:

  1. 返回 this[[SendGroup]]

给定 value,setter 步骤如下:

  1. 如果 value 非 null,且 value.[[Transport]] 不是 this.[[Transport]], 则抛出 一个 InvalidStateError

  2. this.[[SendGroup]] 设为 value

sendOrder类型为 long long

getter 步骤如下:

  1. 返回 this[[SendOrder]]

给定 value,setter 步骤如下:

  1. this.[[SendOrder]] 设为 value

7.2. 方法

getStats()

收集特定于此 WebTransportSendStream 性能的 统计信息, 并异步报告结果。

在被调用时,用户代理必须运行以下步骤:

  1. transportthis.[[Transport]]

  2. p 为一个新的 promise。

  3. 并行地运行以下步骤:

    1. gatheredStats 为准确填充 WebTransportSendStreamStats字典成员所需的、 特定于 this WebTransportSendStream 的统计信息列表

    2. transport 将一个网络任务排队 以运行以下步骤:

      1. stats 为一个新的 WebTransportSendStreamStats 对象。

      2. 对于用户代理希望公开的 stats 的每个成员 member, 将 member 设置gatheredStats 中对应的条目

      3. stats 兑现 p

  4. 返回 p

getWriter()

this 流创建一个 WebTransportWriter

当调用 getWriter 时,返回以 this 创建一个 WebTransportWriter 的结果。

7.3. 内部插槽

WebTransportSendStream 拥有以下内部槽。

内部槽 说明(非规范性
[[InternalStream]] 一个出站单向双向 WebTransport 流
[[PendingOperation]] 表示挂起写入或关闭操作的 promise,或为 null。
[[Transport]] 拥有该 WebTransportWebTransportSendStream
[[SendGroup]] 一个可选的 WebTransportSendGroup, 或 null。
[[SendOrder]] 可选的发送顺序号,默认值为 0。
[[AtomicWriteRequests]] promise 的有序集合, 用于追踪排队提交至底层 sink 并要求原子操作的写入请求子集。
[[InsideSynchronousAtomicWrite]] 布尔值,仅在执行 atomicWrite 方法的同步部分时为 true。
[[BytesWritten]] 已写入到流中的字节数。
[[CommittedOffset]] 流内偏移量,记录即使在流已中止发送时 也将交付给对端的字节数; 见 [RELIABLE-RESET]

7.4. 过程

创建一个 WebTransportSendStream ,其参数为一个 外发单向双向 WebTransport 流 internalStream,一个 WebTransport transportsendGroup,以及 sendOrder,请执行如下步骤:

  1. stream 为一个 新建的 WebTransportSendStream, 其属性如下:

    [[InternalStream]]

    internalStream

    [[PendingOperation]]

    null

    [[Transport]]

    transport

    [[SendGroup]]

    sendGroup

    [[SendOrder]]

    sendOrder

    [[AtomicWriteRequests]]

    一个空的 有序 promise 集合

    [[InsideSynchronousAtomicWrite]]

    false

    [[BytesWritten]]

    0

    [[CommittedOffset]]

    0

  2. writeAlgorithm 为一个动作,该动作 写入 chunkstream(参数为 chunk 时)。

  3. closeAlgorithm 为一个动作,该动作 关闭 stream

  4. abortAlgorithm 为一个动作,该动作 终止 stream,参数为 reason

  5. 设置 streamwriteAlgorithm 设为 writeAlgorithmcloseAlgorithm 设为 closeAlgorithmabortAlgorithm 设为 abortAlgorithm

  6. abortSignalstream 的 [[controller]].[[abortController]].[[signal]]。

  7. 添加如下步骤到 abortSignal

    1. pendingOperationstream.[[PendingOperation]]

    2. 如果 pendingOperation 为 null,则中止这些步骤。

    3. stream.[[PendingOperation]] 设为 null。

    4. reasonabortSignal中止原因

    5. promise终止 stream ,参数为 reason 的结果。

    6. 在 promise fulfilled 时拒绝 pendingOperation,原因为 reason

  8. 追加 streamtransport.[[SendStreams]]

  9. 返回 stream

要向一个 WebTransportSendStream stream 写入 chunk,运行以下步骤:
  1. transportstream.[[Transport]]

  2. 如果 chunk 不是一个 BufferSource, 则返回一个被拒绝的 promise,拒绝原因为 TypeError

  3. promise 为一个新的 promise。

  4. byteschunk 所表示的字节 序列的副本。

  5. 如果 bytes长度为 0, 则使用 undefined 兑现 promise,并返回 promise

  6. stream.[[PendingOperation]] 设为 promise

  7. inFlightWriteRequeststream.inFlightWriteRequest

  8. 如果 stream.[[AtomicWriteRequests]] 包含 inFlightWriteRequest,或者 stream.[[InsideSynchronousAtomicWrite]] 为 true,则令 atomic 为 true;否则为 false。

  9. 并行运行以下步骤:

    1. 如果 atomic 为 true,且当前流量 控制窗口太小,无法完整发送 bytes, 则中止其余步骤,并排入一个网络任务,其关联的 transporttransport, 以运行这些子步骤:

      1. stream.[[PendingOperation]] 设为 null。

      2. stream中止 所有原子写入请求

    2. 否则,在 stream.[[InternalStream]]发送 bytes,并等待操作完成。 此发送必须遵循发送顺序规则

      用户代理可以有一个缓冲区以改进传输性能。这样的缓冲区 应该具有固定的上限,以便将背压信息传达给 WebTransportSendStream 的用户。

      这里我们并行地访问 stream.[[SendOrder]]。 用户代理应该在发送期间响应这些值的实时更新,但 细节是实现定义的

      注: 重传的排序是 实现定义的, 但强烈鼓励用户代理优先重传具有较高 [[SendOrder]] 值的数据。

      此发送不得以其他方式饥饿, 除非是由于流量控制原因,或错误

      用户代理应该在所有未被饥饿的流之间公平地分配带宽。

      注: 这里的公平性定义是 实现定义的

    3. 如果上一步由于网络错误而失败,则中止其余步骤。

      注: 我们不在此处拒绝 promise,因为我们会在别处处理网络错误,并且那些步骤 会拒绝 stream.[[PendingOperation]]

    4. 否则,排入一个网络任务,其关联的 transporttransport, 以运行这些步骤:

      1. stream.[[PendingOperation]] 设为 null。

      2. bytes 的长度加到 stream.[[BytesWritten]]

      3. 如果 stream.[[AtomicWriteRequests]] 包含 inFlightWriteRequest,则移除 inFlightWriteRequest

      4. 使用 undefined 兑现 promise

  10. 返回 promise

注: 从此算法返回的 promise(或者 write(chunk)) 的兑现一定意味着该块已经被 服务器确认 [QUIC]。它可能只意味着该 块已附加到缓冲区。要确保 该块到达服务器,服务器需要发送应用层确认消息。

关闭一个 WebTransportSendStream stream,运行以下步骤:
  1. transportstream.[[Transport]]

  2. promise 为一个新的 promise。

  3. transport.[[SendStreams]]移除 stream

  4. stream.[[PendingOperation]] 设为 promise

  5. 并行运行以下步骤:

    1. stream.[[InternalStream]]发送 FIN, 并等待该操作 完成。

    2. 等待 stream.[[InternalStream]] 进入“所有数据已提交”状态。[QUIC]

    3. 排入一个网络任务,其关联的 transporttransport,以运行这些步骤:

      1. stream.[[PendingOperation]] 设为 null。

      2. 使用 undefined 兑现 promise

  6. 返回 promise

要以 reason 中止一个 WebTransportSendStream stream,运行以下步骤:
  1. transportstream.[[Transport]]

  2. promise 为一个新的 promise。

  3. code 为 0。

  4. transport.[[SendStreams]]移除 stream

  5. 如果 reason 是一个 WebTransportError, 且 reason.[[StreamErrorCode]] 不为 null,则将 code 设为 reason.[[StreamErrorCode]]

  6. 如果 code < 0,则将 code 设为 0。

  7. 如果 code > 4294967295,则将 code 设为 4294967295。

  8. committedOffsetstream.[[CommittedOffset]]

    注: code 的有效值 范围为 0 到 4294967295(含)。如果底层连接正在 使用 HTTP/3,则该代码会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 范围内的数字,如 [WEB-TRANSPORT-HTTP3] 中所述。

  9. 并行运行以下步骤:

    1. stream.[[InternalStream]] 上以 codecommittedOffset 中止发送

    2. 排入一个网络任务,其关联的 transporttransport,以使用 undefined 兑现 promise

  10. 返回 promise

要在一个 WebTransportSendStream stream中止所有原子写入请求,运行以下步骤:
  1. writeRequestsstream.writeRequests

  2. requestsToAbortstream.[[AtomicWriteRequests]]

  3. 如果 writeRequests 包含一个 不在 requestsToAbort 中的 promise,则 使用 AbortError 错误化 stream, 并中止这些步骤。

  4. 清空 stream.[[AtomicWriteRequests]]

  5. 对于 requestsToAbort 中的每个 promise,使用 AbortError 拒绝 promise

  6. 并行地,对于 requestsToAbort 中的每个 promise,中止与 promise 关联的字节 发送

7.5. 接收来自服务器的中止信号

每当与 WebTransportSendStream stream 关联的 WebTransport 流从服务器收到 接收已中止信号时,运行以下 步骤:
  1. transportstream.[[Transport]]

  2. code 为附加到接收已中止信号上的应用协议错误码。

    注:code 的有效值为 0 到 4294967295(含)。如果底层连接 使用 HTTP/3,则该代码将被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 中的一个数字,如 [WEB-TRANSPORT-HTTP3] 中所述。

  3. transport 将一个网络任务排队,以运行这些步骤:

    1. 如果 transport.[[State]]"closed""failed",则中止这些步骤。

    2. transport.[[SendStreams]]移除 stream

    3. error 为一个新创建WebTransportError, 其 source"stream",并且 streamErrorCodecode

    4. 如果 stream.[[PendingOperation]] 不为 null,则用 error 拒绝 stream.[[PendingOperation]]

    5. error 使 stream 出错。

7.6. WebTransportSendStreamStats 字典

WebTransportSendStreamStats 字典 包括一个 WebTransportSendStream 的特定统计信息。

dictionary WebTransportSendStreamStats {
  unsigned long long bytesWritten;
  unsigned long long bytesSent;
  unsigned long long bytesAcknowledged;
};

该字典应具有以下属性:

bytesWritten 类型为 unsigned long long

应用已经成功写入此 WebTransportSendStream 的总字节数。该数值只会递增。

bytesSent 类型为 unsigned long long

对应用写入此 WebTransportSendStream 的字节有多少至少发送过一次的进度指标。该数值只会递增,且始终小于等于 bytesWritten

注意: 此为仅本流应用层数据的发送进度,不包含任何网络开销。

bytesAcknowledged 类型为 unsigned long long

对应用写入此 WebTransportSendStream 的字节已被服务端通过 QUIC 的 ACK 机制确认接收的进度指标。仅统计第一个未确认字节之前的所有连续字节。该数值只会递增,且始终小于等于 bytesSent

注意: 当连接为 HTTP/2 时,该值会与 bytesSent 保持一致。

8. 接口 WebTransportSendGroup

WebTransportSendGroup 是一个可选的组织对象,用于跟踪分布在许多个单独 (通常是 严格排序的) WebTransportSendStream 上的数据传输。

WebTransportSendStreamWebTransportDatagramsWritable, 在创建或通过其 sendGroup 属性赋值后, 都可以在任意时刻被归组 到至多一个 WebTransportSendGroup空 sendGroup。 默认情况下, WebTransportSendStreamWebTransportDatagramsWritable 被分配到 空 sendGroup

用户代理在分配带宽以发送 WebTransportSendStream 时, 将 WebTransportSendGroup 视为同等对象。 每个 WebTransportSendGroup 还建立了独立的编号空间, 用于评估 sendOrder 数字。

[Exposed=(Window,Worker), SecureContext]
interface WebTransportSendGroup {
  Promise<WebTransportSendStreamStats> getStats();
};

一个 WebTransportSendGroup 总是通过 创建过程生成。

8.1. 方法

getStats()

聚合 this sendGroup 下分组的所有 WebTransportSendStream 的统计信息,并异步报告结果。

在被调用时,用户代理必须运行以下步骤:

  1. transportthis.[[Transport]]

  2. p 为一个新的 promise。

  3. streams 为所有 WebTransportSendStream, 其 [[SendGroup]]this

  4. 并行地运行以下步骤:

    1. gatheredStats 为准确填充 WebTransportSendStreamStats字典成员所需的、 来自 streams 中所有流的聚合统计信息列表

    2. transport 将一个网络任务排队 以运行以下步骤:

      1. stats 为一个新的 WebTransportSendStreamStats 对象。

      2. 对于用户代理希望公开的 stats 的每个成员 member, 将 member 设置gatheredStats 中对应的条目

      3. stats 兑现 p

  5. 返回 p

8.2. 内部槽

一个 WebTransportSendGroup 拥有以下内部槽。

内部槽 描述 (非规范性)
[[Transport]] 拥有此 WebTransport 对象的 WebTransportSendGroup

8.3. 过程

创建 WebTransportSendGroup, 并指定 WebTransport transport,请执行以下步骤:

  1. sendGroup新建WebTransportSendGroup, 其中:

    [[Transport]]

    transport

  2. 返回 sendGroup

9. 接口 WebTransportReceiveStream

WebTransportReceiveStream 是一个 ReadableStream ,用于提供入向流特性,支持 入向单向双向 WebTransport 流

它是一个 ReadableStream ,元素类型为 Uint8Array ,可读取以消费从服务器接收到的数据。WebTransportReceiveStream 是一个 可读字节流, 因此允许消费者使用 BYOB reader 以及 默认 reader

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportReceiveStream : ReadableStream {
  Promise<WebTransportReceiveStreamStats> getStats();
};

一个 WebTransportReceiveStream 总是通过 创建过程生成。

WebTransportReceiveStream传输步骤接收传输步骤ReadableStream 的步骤一致。

9.1. 方法

getStats()

收集特定于此 WebTransportReceiveStream 性能的 统计信息, 并异步报告结果。

在被调用时,用户代理必须运行以下步骤:

  1. transportthis.[[Transport]]

  2. p 为一个新的 promise。

  3. 并行地运行以下步骤:

    1. gatheredStats 为准确填充 WebTransportReceiveStreamStats字典成员所需的、 特定于 this WebTransportReceiveStream 的统计信息列表

    2. transport 将一个网络任务排队 以运行以下步骤:

      1. stats 为一个新的 WebTransportReceiveStreamStats 对象。

      2. 对于用户代理希望公开的 stats 的每个成员 member, 将 member 设置gatheredStats 中对应的条目

      3. stats 兑现 p

  4. 返回 p

9.2. 内部槽

WebTransportReceiveStream 拥有以下内部槽。

内部槽 说明(非规范性
[[InternalStream]] 一个入站单向双向 WebTransport 流
[[Transport]] 拥有该 WebTransportWebTransportReceiveStream 对象。

9.3. 过程

要用一个传入单向双向 WebTransport 流 internalStream 和一个 WebTransport transport 创建一个 WebTransportReceiveStream, 运行以下步骤:

  1. stream 为一个新的 WebTransportReceiveStream, 并具有:

    [[InternalStream]]

    internalStream

    [[Transport]]

    transport

  2. pullAlgorithm 为一个从 stream 拉取字节的动作。

  3. cancelAlgorithm 为一个在给定 reason 时,用 reason 取消 stream 的动作。

  4. 用设置为 pullAlgorithmpullAlgorithm 和设置为 cancelAlgorithmcancelAlgorithmstream 设置字节读取支持

  5. stream 追加transport.[[ReceiveStreams]]

  6. 返回 stream

要从一个 WebTransportReceiveStream stream 拉取字节,运行以下步骤。

  1. transportstream.[[Transport]]

  2. internalStreamstream.[[InternalStream]]

  3. promise 为一个新的 promise。

  4. bufferoffsetmaxBytes 为 null。

  5. 如果 stream当前 BYOB 请求视图对于 stream 不为 null:

    1. offset 设为 stream当前 BYOB 请求 视图.[[ByteOffset]]。

    2. maxBytes 设为 stream当前 BYOB 请求 视图字节长度

    3. buffer 设为 stream当前 BYOB 请求 视图底层缓冲区

  6. 否则:

    1. offset 设为 0。

    2. maxBytes 设为一个实现定义的大小。

    3. buffer 设为一个大小为 maxBytes ArrayBuffer。 如果分配该 ArrayBuffer 失败,则返回一个被拒绝的 promise,拒绝原因为 RangeError

  7. 并行运行以下步骤:

    1. 将从 internalStream 读取到的字节写入 buffer,偏移量为 offset,最多写入 maxBytes 字节。等待 至少读取到一个字节,或收到 FIN。令 read 为读取的字节数,并令 hasReceivedFIN 表示 FIN 是否随同收到。

      用户代理可以有一个缓冲区以改进传输性能。这样的缓冲区 应该具有固定的上限,以便将背压信息传达给服务器。

      注: 此操作可能会在填满整个 buffer 之前返回。

    2. 如果上一步失败,则中止其余步骤。

      注: 我们不在此处拒绝 promise,因为我们会在别处处理网络错误,并且那些步骤会 错误化 stream,这会拒绝任何 等待此次拉取的读取请求。

    3. 排入一个网络任务,其关联的 transporttransport,以运行以下步骤:

      注: 如果上面描述的缓冲区 在此过程运行所在的事件循环中可用, 则以下步骤可以立即运行。

      1. 如果 read > 0:

        1. view 设为一个新的 Uint8Array, 其使用 bufferoffsetread

        2. view 入队stream 中。

      2. 如果 hasReceivedFIN 为 true:

        1. transport.[[ReceiveStreams]]移除 stream

        2. 关闭 stream

      3. 使用 undefined 兑现 promise

  8. 返回 promise

要以 reason 取消一个 WebTransportReceiveStream stream,运行以下 步骤。

  1. transportstream.[[Transport]]

  2. internalStreamstream.[[InternalStream]]

  3. promise 为一个新的 promise。

  4. code 为 0。

  5. 如果 reason 是一个 WebTransportError, 且 reason.[[StreamErrorCode]] 不为 null,则将 code 设为 reason.[[StreamErrorCode]]

  6. 如果 code < 0,则将 code 设为 0。

  7. 如果 code > 4294967295,则将 code 设为 4294967295。

    注: code 的有效值 范围为 0 到 4294967295(含)。如果底层连接正在 使用 HTTP/3,则该代码会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 范围内的数字,如 [WEB-TRANSPORT-HTTP3] 中所述。

  8. transport.[[SendStreams]]移除 stream

  9. 并行运行以下步骤:

    1. internalStream 上以 code 中止接收

    2. 排入一个网络任务,其关联的 transporttransport,以运行以下步骤:

      注: 如果上面描述的缓冲区 在此过程运行所在的事件循环中可用, 则以下步骤可以立即运行。

      1. transport.[[ReceiveStreams]]移除 stream

      2. 使用 undefined 兑现 promise

  10. 返回 promise

9.4. 接收来自服务器的发送中止信号

每当与 WebTransportReceiveStream stream 关联的 WebTransport 流从服务器收到 发送已中止信号时,运行以下步骤:
  1. transportstream.[[Transport]]

  2. code 为附加到发送已中止信号上的应用协议错误码。

    注:code 的有效值为 0 到 4294967295(含)。如果底层连接 使用 HTTP/3,则该代码将被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 中的一个数字,如 [WEB-TRANSPORT-HTTP3] 中所述。

  3. transport 将一个网络任务排队,以运行这些步骤:

    1. 如果 transport.[[State]]"closed""failed",则中止这些步骤。

    2. transport.[[ReceiveStreams]]移除 stream

    3. error 为一个新创建WebTransportError, 其 source"stream",并且 streamErrorCodecode

    4. error 使 stream 出错。

9.5. WebTransportReceiveStreamStats 字典

WebTransportReceiveStreamStats 字典 包括一个 WebTransportReceiveStream 的特定统计信息。

dictionary WebTransportReceiveStreamStats {
  unsigned long long bytesReceived;
  unsigned long long bytesRead;
};

字典应具有以下属性:

bytesReceived 类型为 unsigned long long

用于指示服务端应用发送到此 WebTransportReceiveStream 的字节中,已成功接收的进度。 只统计第一个缺失字节之前的所有连续字节。该数值只会递增。

注意: 仅为单条流中接收到的应用层数据进度,不包括任何网络开销。

bytesRead 类型为 unsigned long long

应用已从此 WebTransportReceiveStream 成功读取的字节总数。该数值只会递增,且始终小于等于 bytesReceived

10. 接口 WebTransportBidirectionalStream

[Exposed=(Window,Worker), SecureContext]
interface WebTransportBidirectionalStream {
  readonly attribute WebTransportReceiveStream readable;
  readonly attribute WebTransportSendStream writable;
};

10.1. 内部插槽

一个 WebTransportBidirectionalStream 具有以下内部槽。

内部槽 描述(非规范性
[[Readable]] 一个 WebTransportReceiveStream
[[Writable]] 一个 WebTransportSendStream
[[Transport]] 拥有此对象的 WebTransport 对象 WebTransportBidirectionalStream

10.2. 属性

readable类型为 WebTransportReceiveStream,readonly

getter 步骤是返回 this[[Readable]]

writable类型为 WebTransportSendStream,readonly

getter 步骤是返回 this[[Writable]]

10.3. 过程

创建一个 WebTransportBidirectionalStream ,给定一个 双向 WebTransport 流 internalStream、一个 WebTransport 对象 transport 和一个 sendOrder,执行以下步骤:
  1. readable创建 WebTransportReceiveStream 的结果,参数为 internalStreamtransport

  2. writable创建 WebTransportSendStream 的结果,参数为 internalStreamtransportsendOrder

  3. stream新建WebTransportBidirectionalStream,其属性如下:

    [[Readable]]

    readable

    [[Writable]]

    writable

    [[Transport]]

    transport

  4. 返回 stream

11. WebTransportWriter 接口

WebTransportWriterWritableStreamDefaultWriter 的子类, 增加了两个方法。

WebTransportWriter 始终通过 create 过程创建。

[Exposed=*, SecureContext]
interface WebTransportWriter : WritableStreamDefaultWriter {
  Promise<undefined> atomicWrite(optional any chunk);
  undefined commit();
};

11.1. 方法

atomicWrite(chunk)

atomicWrite 方法会在给定给它的 chunk 无法在发送时当前的流量控制 窗口内完整发送时拒绝。此行为旨在满足对流量控制 死锁敏感的专门事务性应用([RFC9308] 第 4.4 节)。

注:atomicWrite 在发送了一些数据后仍可能拒绝。虽然它 在流量控制方面提供原子性,但可能发生其他错误。 atomicWrite 不会阻止数据被拆分到不同数据包之间, 也不会阻止其与其他数据交错。只有发送方知道 atomicWrite 是否因缺少可用的流量控制信用而失败。

注:如果原子写入排在非原子写入之后, 它们仍可能被阻塞。如果 原子写入被拒绝,则当时排在它之后的所有内容 也会被拒绝。以这种方式被拒绝的任何非原子写入都会 使该流出错。因此鼓励应用 始终 await 原子写入。

在被调用时,用户代理必须运行以下步骤:

  1. streamthis.stream

  2. 如果 stream 为 undefined,则返回一个被拒绝的 promise,拒绝原因为 TypeError

  3. stream.[[InsideSynchronousAtomicWrite]] 设为 true。

  4. p 为将 chunk 写入 this 的结果。

  5. stream.[[InsideSynchronousAtomicWrite]] 设为 false。

  6. p 追加stream.[[AtomicWriteRequests]]

  7. 返回以以下步骤对 p 作出反应的结果:

    1. 如果 stream.[[AtomicWriteRequests]] 包含 p, 则移除 p

    2. 如果 p 被以原因 r 拒绝,则返回一个被拒绝的 promise,拒绝原因为 r

    3. 返回 undefined。

commit()

commit 方法会将流的 [[CommittedOffset]] 更新为该流已经写入的字节数 ([[BytesWritten]])。 这样可确保这些字节即使在写入被中止、 导致流中止发送后, 也会被可靠传递到对端。 相关机制见 [RELIABLE-RESET]

注: 这无法保证连接失败时数据一定能传递, 只保证流已中止发送时传递。

当对 stream 调用 commit 时,用户代理必须执行以下步骤:

  1. stream.[[CommittedOffset]] 设为 stream.[[BytesWritten]] 的值。

11.2. 过程

创建 一个 WebTransportWriter, 给定 WebTransportSendStream stream,执行以下步骤:

  1. writer新的 WebTransportWriter

  2. stream设置 writer

  3. 返回 writer

12. WebTransportError 接口

WebTransportErrorDOMException 的子类,表示:

[Exposed=(Window,Worker), Serializable, SecureContext]
interface WebTransportError : DOMException {
  constructor(optional DOMString message = "", optional WebTransportErrorOptions options = {});

  readonly attribute WebTransportErrorSource source;
  readonly attribute unsigned long? streamErrorCode;
};

dictionary WebTransportErrorOptions {
  WebTransportErrorSource source = "stream";
  [Clamp] unsigned long? streamErrorCode = null;
};

enum WebTransportErrorSource {
  "stream",
  "session",
};

12.1. 内部插槽

一个 WebTransportError 具有以下内部槽。

内部槽 描述 (非规范性)
[[Source]] 一个 WebTransportErrorSource ,指示此错误的来源。
[[StreamErrorCode]] 此错误的应用协议错误代码,或 null。

12.2. 构造函数

new WebTransportError(message, options) 构造函数步骤如下:

  1. thisname 设置为 "WebTransportError"

  2. thismessage 设置为 message

  3. this 的内部槽设置如下:

    [[Source]]

    options.source

    [[StreamErrorCode]]

    options.streamErrorCode

    注: 此 name 没有 legacy code 映射,因此 thiscode 为 0。

12.3. 属性

source类型为 WebTransportErrorSource,readonly

getter 步骤是返回 this[[Source]]

streamErrorCode类型为 unsigned long,readonly,可为 null

getter 步骤是返回 this[[StreamErrorCode]]

12.4. 序列化

WebTransportError 对象是 可序列化对象。 它们的 序列化步骤,给定 valueserialized,如下:

  1. 运行 DOMException序列化步骤,给定 valueserialized

  2. serialized.[[Source]] 设置为 value.[[Source]]

  3. serialized.[[StreamErrorCode]] 设置为 value.[[StreamErrorCode]]

它们的 反序列化步骤,给定 serializedvalue,如下:

  1. 运行 DOMException反序列化步骤,给定 serializedvalue

  2. value.[[Source]] 设置为 serialized.[[Source]]

  3. value.[[StreamErrorCode]] 设置为 serialized.[[StreamErrorCode]]

13. 协议映射

此部分为非规范性内容。

本节描述了本规范中定义的方法的底层协议行为,使用 [WEB-TRANSPORT-OVERVIEW]。 由于缓冲,因果关系可能不会立即显现。

WebTransport协议动作 API效果
会话开始排水 await wt.draining

如果 底层连接 使用 HTTP/3,则适用于从 [WEB-TRANSPORT-HTTP3] 的以下协议行为。

WebTransportError 错误中的应用 streamErrorCode 转换为 httpErrorCode,反之亦然,如 [WEB-TRANSPORT-HTTP3] 第4.3节 中所述。

API 方法 QUIC 协议操作
writable.abort(error) 中止发送(STREAM),带 httpErrorCode 以及 对应于该 [[CommittedOffset]] 的偏移(外加任意流头);详见 [RELIABLE-RESET]
writable.close() 发送 STREAM,并设置 FIN 标志位
writable.getWriter().write(chunk)() 发送 STREAM
writable.getWriter().close() 发送 STREAM,并设置 FIN 标志位
writable.getWriter().abort(error) 中止发送(STREAM),带 httpErrorCode 以及 对应于该 [[CommittedOffset]] 的偏移(外加任意流头);详见 [RELIABLE-RESET]
readable.cancel(error) 中止接收(STREAM),带 httpErrorCode
readable.getReader().cancel(error) 中止接收(STREAM),带 httpErrorCode
wt.close(closeInfo) 终止会话,带 closeInfo
QUIC 协议操作 API 效果
收到 STOP_SENDING(带 httpErrorCode) 使 writable 报错,带 streamErrorCode
收到 STREAM (await readable.getReader().read()).value
收到 STREAM(带 FIN bit) (await readable.getReader().read()).done
收到 RESET_STREAM(带 httpErrorCode) 使 readable 报错,带 streamErrorCode
会话被正常终止,带 closeInfo
(await wt.closed).closeInfo, 并且 使 所有打开的流报错
网络错误
(await wt.closed) reject,并且 使 所有打开的流报错

注意:[QUIC] RFC9000 §3.2 所述, 收到 RESET_STREAM 帧或 RESET_STREAM_AT 帧([RELIABLE-RESET]) 并不总是会通知应用层。 重置信号可以立即触发,导致流数据传递被中断,未消费的数据会被丢弃。 但协议不要求必须立即通知,信号可能会延迟,以便传递 RESET_STREAM_AT 帧中的 Reliable Size 字段所指示的数据。 如果流数据已完整接收但尚未被应用读取,则发送中止信号可被抑制。 WebTransport 始终使用 RESET_STREAM_AT 帧,以确保流头部能够可靠传递; 参见 §4.1§4.2 [WEB-TRANSPORT-HTTP3]

HTTP/3 协议动作 API效果
会话开始排水 await wt.draining

如果底层连接使用 HTTP/2,则适用 [WEB-TRANSPORT-HTTP2] 中的协议行为。注意,与 HTTP/3 不同,流错误码不需要转换为 HTTP 错误码,反之亦然。

API 方法 HTTP/2 协议操作
writable.abort(error) 中止发送 WT_STREAM,附带 error
writable.close() 发送 带 FIN 标志位的 WT_STREAM
writable.getWriter().write() 发送 WT_STREAM
writable.getWriter().close() 发送 带 FIN 标志位的 WT_STREAM
writable.getWriter().abort(error) 中止发送 WT_STREAM,附带 error
readable.cancel(error) 中止接收 WT_STREAM,附带 error
readable.getReader().cancel(error) 中止接收 WT_STREAM,附带 error
wt.close(closeInfo) 终止会话,带 closeInfo
HTTP/2 协议操作 API 效果
收到 WT_STOP_SENDING,附带 error 使 writable 报错,带 streamErrorCode
收到 WT_STREAM (await readable.getReader().read()).value
收到 带 FIN 标志位的 WT_STREAM (await readable.getReader().read()).done
收到 WT_RESET_STREAM,附带 error 使 readable 报错,带 streamErrorCode
会话被正常终止,带 closeInfo
(await wt.closed).closeInfo, 并且 使 所有打开的流报错
网络错误
(await wt.closed) reject,并且 使 所有打开的流报错
会话开始draining await wt.draining

14. 隐私与安全注意事项

此部分为非规范性内容;它未指定任何新的行为,而是总结了规范其他部分中已经存在的信息。

14.1. 通信机密性

通信正在进行的事实无法对能够观察网络的对手隐瞒,因此这必须被视为公开信息。

本文件中描述的所有传输协议都使用 TLS [RFC9846] 或语义上等效的协议,从而提供了 TLS 的所有安全属性,包括流量的机密性和完整性。基于 HTTP 的 WebTransport 使用与出站 HTTP 请求相同的证书验证机制,因此依赖于相同的公钥基础设施来验证远程服务器的身份。在 WebTransport 中,证书验证错误是致命的;没有允许绕过证书验证的中间页面。

14.2. 状态持久性

WebTransport 本身不会创建任何新的唯一标识符或持久存储状态的新方法,也不会自动向服务器公开任何现有的持久状态。例如,[WEB-TRANSPORT-HTTP3][WEB-TRANSPORT-HTTP2] 都不发送 Cookies,也不支持 HTTP 身份验证或缓存失效机制。由于它们确实使用 TLS,它们继承了 TLS 的持久状态,例如 TLS 会话票据,这虽然对被动网络观察者不可见,但可能会被服务器用于关联来自同一客户端的不同连接。

14.3. 协议安全性

WebTransport 强加了一组要求,如 [WEB-TRANSPORT-OVERVIEW] 中所述,包括:

  1. 确保远程服务器知晓正在使用 WebTransport 协议,并确认远程服务器愿意使用 WebTransport 协议。[WEB-TRANSPORT-HTTP3] 通过 ALPN 与 [RFC7301] 的组合、HTTP/3 的设置以及 :protocol伪首部字段 来标识 WebTransport 协议。[WEB-TRANSPORT-HTTP2] 则通过 ALPN、HTTP/2 的设置以及 :protocol伪首部字段 来标识 WebTransport 协议。

  2. 允许服务器根据发起传输会话的资源的来源来过滤连接。会话建立请求中的 Origin 首部字段携带此信息。

协议安全相关的注意事项,请参见 安全注意事项章节, [WEB-TRANSPORT-OVERVIEW] 第 6 节[WEB-TRANSPORT-HTTP3] 第 8 节,以及 [WEB-TRANSPORT-HTTP2] 第 9 节

网络 API 通常可用于扫描本地网络以查找可用主机,因此可用于指纹识别和其他形式的攻击。WebTransport 遵循 WebSocket 方法 解决此问题: 直到端点被验证为 WebTransport 端点之前,具体的连接错误不会返回;因此,Web 应用程序无法区分不存在的端点和不愿意接受 Web 连接的端点。

14.4. 使用证书哈希进行服务器身份验证

通常,用户代理通过验证所提供的 TLS 服务器证书的有效性与 URL 中的服务器名称 [RFC9525] 相比来对其自身与远程端点之间的 TLS 连接进行身份验证。这是通过将服务器证书链接到用户代理维护的信任锚之一来实现的;相关的信任锚负责对证书中的服务器名称进行身份验证。我们将此系统称为 Web PKI。

此 API 为 Web 应用程序提供了一种连接到远程网络端点的能力,该端点通过指定的服务器证书而不是其服务器名称进行身份验证。此机制使连接到难以获取长期证书的端点成为可能,包括那些本质上是短暂的主机(例如短期虚拟机),或不可公开路由的主机。由于此机制替代了基于 Web PKI 的单个连接身份验证,我们需要比较两者的安全属性。

只有在远程服务器拥有与指定证书的公钥相对应的私钥时,它才能成功执行 TLS 握手。API 使用其哈希值来标识证书。只要所使用的加密哈希函数具有第二原像抗性,这种方法才是安全的。本文档中唯一定义的函数是 SHA-256;API 提供了一种通过允许指定多个算法-哈希对来引入新哈希函数的方法。

需要注意的是,Web PKI 除了简单地为服务器名称建立信任链之外,还提供了额外的安全机制。其中之一是处理证书吊销。在使用的证书是短暂的情况下,这种机制没有必要。在其他情况下,Web 应用程序必须考虑证书哈希值的供应机制;例如,如果哈希值作为缓存的 HTTP 资源提供,则在相应证书因泄露而被轮换时需要使缓存失效。Web PKI 提供的另一个安全功能是针对密钥生成的某些问题的保障,例如拒绝具有已知弱密钥的证书;虽然本文档没有提供任何具体的指导,但浏览器可以作为实现定义的行为的一部分拒绝这些证书。

Web PKI 对证书实施了过期周期要求。此要求限制了潜在密钥泄露的范围;它还迫使服务器运营商设计支持并积极执行密钥轮换的系统。出于这个原因,WebTransport 对证书施加了类似的过期要求;由于证书预计是短暂或短期的,因此过期周期限制为两周。两周的限制是在尽可能低地设置过期限制以最大限度地减少密钥泄露的后果之间,以及保持其足够高以适应设备之间的时钟偏差,并降低客户端和服务器端同步证书的成本之间的平衡。

WebTransport API 允许应用程序一次指定多个证书哈希值,从而允许客户端在新证书推出期间接受多个证书。

WebRTC 中类似的机制不同,WebTransport 中的服务器证书哈希 API 不提供任何身份验证客户端的方法;客户端知道服务器证书是什么或如何联系它这一事实并不足够。应用程序如果需要,必须在带内建立客户端的身份。

14.5. 指纹识别与跟踪

此 API 使站点能够生成网络活动并密切观察此活动的效果。通过这种方式获取的信息可能是识别性的信息。

重要的是要认识到,其他 Web 平台 API(例如 fetch()WebSocket) 也提供了非常类似的网络能力。 因此,添加 WebTransport 对隐私造成的净 不利影响很小。本节中的 考量同样适用于其他网络能力。

测量网络特性需要使用网络并测量该使用的效果,而这两者都由此 API 启用。WebTransport 为站点提供了向其选择的服务器生成网络活动并观察效果的能力。可以观察网络路径的稳定属性和网络使用的动态效果。

有关网络的信息可以通过服务器自己的网络堆栈直接获得,通过客户端消耗或传输数据的速率间接获得,或者作为由 API 提供的统计信息的一部分获得(参见 § 6.13 WebTransportConnectionStats Dictionary)。因此,对用户代理信息的限制并不是管理这些隐私风险的唯一机制。

14.5.1. 静态观察

站点可以观察用户代理与选定服务器之间的可用网络容量或往返时间(RTT)。当与其他跟踪矢量结合时,这些信息可能具有识别性。RTT 还可以揭示用户代理的物理位置,尤其是在可以从多个观察点进行多次测量的情况下。

尽管网络是共享的,但网络使用通常是零散的,这意味着站点通常可以观察未受争用或负载轻的网络路径的容量和往返时间。这些属性对于许多人来说是稳定的,因为他们的网络位置没有改变,网络瓶颈的位置--决定可用容量--可能靠近用户代理。

14.5.2. 共享网络

受争用的链接为站点提供了启用跨站点识别的机会,这可能会被用来执行未经授权的跟踪 [UNSANCTIONED-TRACKING]。 网络容量是有限的共享资源,因此用户代理同时访问不同站点可能会揭示每个站点呈现的身份之间的连接。

在一个站点上使用网络功能会减少其他站点可用的容量,可以使用网络 API 观察到这一点。网络使用和指标可能会动态变化,因此任何变化都可以实时观察到。这可能允许站点增加信心,即不同站点上的活动来自同一用户。

用户代理可以限制或降低对反馈机制(例如统计信息(§ 6.13 WebTransportConnectionStats Dictionary))的访问,针对不活跃或未获得焦点的站点(HTML § 6.6 Focus)。如所述,这并不能阻止服务器观察网络中的变化。

14.5.3. 池化会话

与共享网络场景类似,当会话在单个连接上池化时,一个会话的信息会受到另一个会话活动的影响。一个会话可以推断关于另一个会话活动的信息,例如另一个应用程序发送数据的速率。

使用共享连接已经允许服务器关联会话。使用 网络分区键 禁用池化,其中共享会话的使用可能启用不必要的跨站点识别。

15. 示例

15.1. 发送数据报缓冲区

此部分为非规范性内容。

可以通过使用 datagrams' createWritable 方法以及生成的流的 writer 来发送数据报缓冲区。在以下示例中,仅当传输准备好发送时才发送数据报。

async function sendDatagrams(url, datagrams) {
  const wt = new WebTransport(url);
  const writable = wt.datagrams.createWritable();
  const writer = writable.getWriter();
  for (const bytes of datagrams) {
    await writer.ready;
    writer.write(bytes).catch(() => {});
  }
  await writer.close();
}

15.2. 以固定速率发送数据报

此部分为非规范性内容。

无论传输是否准备好发送,通过简单使用 datagrams' createWritable 方法以及生成的流的 writer,而不等待 ready 属性即可以固定速率发送数据报。

// 每100毫秒发送数据报。
async function sendFixedRate(url, createDatagram, ms = 100) {
  const wt = new WebTransport(url);
  const writable = wt.datagrams.createWritable();
  const writer = writable.getWriter();
  const bytes = createDatagram();
  setInterval(() => writer.write(bytes).catch(() => {}), ms);
}

15.3. 接收数据报

此部分为非规范性内容。

可以通过从传输的 datagrams.readable 属性中读取来接收数据报。空值可能表示未能快速处理数据包。

async function receiveDatagrams(url) {
  const wt = new WebTransport(url);
  for await (const datagram of wt.datagrams.readable) {
    // 处理数据报
  }
}

15.4. 使用 BYOB 读取器接收数据报

此部分为非规范性内容。

由于 datagrams可读字节流,你可以为它们获取一个 BYOB 读取器, 这样可以更精确地控制缓冲区分配,从而避免复制。下例将 datagram 读入一个 64 Kibibytes 的内存缓冲区中。

const wt = new WebTransport(url);

for await (const datagram of wt.datagrams.readable) {
  const reader = datagram.getReader({ mode: "byob" });

  let array_buffer = new ArrayBuffer(65536);
  const buffer = await readInto(array_buffer);
}

async function readInto(buffer) {
  let offset = 0;

  while (offset < buffer.byteLength) {
    const {value: view, done} = await reader.read(
        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    buffer = view.buffer;
    if (done) {
      break;
    }
    offset += view.byteLength;
  }

  return buffer;
}

15.5. 发送流

此部分为非规范性内容。

可以通过使用 createUnidirectionalStream 函数以及生成的流的 writer 来发送数据作为单向流。

接收时不会保留写入的块边界,因为字节可能会在传输线上合并。因此建议应用程序提供自己的框架。

async function sendData(url, ...data) {
  const wt = new WebTransport(url);
  const writable = await wt.createUnidirectionalStream();
  const writer = writable.getWriter();
  for (const bytes of data) {
    await writer.ready;
    writer.write(bytes).catch(() => {});
  }
  await writer.close();
}

流规范 不建议 等待 write() 的 Promise。

编码也可以通过管道从一个 ReadableStream 进行,例如使用 TextEncoderStream

async function sendText(url, readableStreamOfTextData) {
  const wt = new WebTransport(url);
  const writable = await wt.createUnidirectionalStream();
  await readableStreamOfTextData
    .pipeThrough(new TextEncoderStream("utf-8"))
    .pipeTo(writable);
}

15.6. 接收传入流

此部分为非规范性内容。

可以通过遍历 incomingUnidirectionalStreams 属性,然后通过遍历其块来消费每个 WebTransportReceiveStream 来读取传入流。

分块由用户代理决定,而不是发送方。

async function receiveData(url, processTheData) {
  const wt = new WebTransport(url);
  for await (const readable of wt.incomingUnidirectionalStreams) {
    // 使用 IFFE 单独消费流,报告每个流的错误
    ((async () => {
      try {
        for await (const bytes of readable) {
          processTheData(bytes);
        }
      } catch (e) {
        console.error(e);
      }
    })());
  }
}

解码也可以通过管道传输到新的 WritableStreams,例如使用 TextDecoderStream。 此示例假定文本输出不应交错,因此一次只读取一个流。

async function receiveText(url, createWritableStreamForTextData) {
  const wt = new WebTransport(url);
  for await (const readable of wt.incomingUnidirectionalStreams) {
    // 顺序消费以避免输出交错,报告每个流的错误
    try {
      await readable
       .pipeThrough(new TextDecoderStream("utf-8"))
       .pipeTo(createWritableStreamForTextData());
    } catch (e) {
      console.error(e);
    }
  }
}

15.7. 使用 BYOB 读取器接收流

此部分为非规范性内容。

由于 WebTransportReceiveStream可读字节流,你可以为其获取一个 BYOB reader, 这样可以更精确地控制缓冲区分配,以避免数据拷贝。下面的示例将 WebTransportReceiveStream 的前 1024 个字节读入一个内存缓冲区。

const wt = new WebTransport(url);

const reader = wt.incomingUnidirectionalStreams.getReader();
const { value: recv_stream, done } = await reader.read();
const byob_reader = recv_stream.getReader({ mode: "byob" });

let array_buffer = new ArrayBuffer(1024);
const buffer = await readInto(array_buffer);

async function readInto(buffer) {
  let offset = 0;

  while (offset < buffer.byteLength) {
    const {value: view, done} = await reader.read(
        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    buffer = view.buffer;
    if (done) {
      break;
    }
    offset += view.byteLength;
  }

  return buffer;
}

15.8. 在流上发送事务性块

本节为非规范性内容。

如需在单向流上发送一段事务型数据,并且只有在无须等待 流控时才全量发送,可以通过 getWriter 方法及其返回的 writer 实现。

async function sendTransactionalData(wt, bytes) {
  const writable = await wt.createUnidirectionalStream();
  const writer = writable.getWriter();
  await writer.ready;
  try {
    await writer.atomicWrite(bytes);
  } catch (e) {
    if (e.name != "AbortError") throw e;
    // 因避免阻塞流控制而被拒绝
    // 只要没有待处理的非原子写入,可写流就保持无错误状态
  } finally {
    writer.releaseLock();
  }
}

15.9. 使用服务器证书哈希

此部分为非规范性内容。

WebTransport 会话可以使用对提供给服务器的证书哈希的检查来覆盖客户端执行的默认信任评估。在下面的示例中,hashValue 是一个 BufferSource, 包含 底层连接 应视为有效的服务器证书的 SHA-256 哈希。

const wt = new WebTransport(url, {
  serverCertificateHashes: [
    {
      algorithm: "sha-256",
      value: hashValue,
    }
  ]
});
await wt.ready;

15.10. 完整示例

此部分为非规范性内容。

此示例说明了 closed 和 ready promise 的使用、客户端或服务器打开单向和双向流,以及发送和接收数据报。

曾经存在于传输的 datagrams 上的 writable 属性很容易通过如下方式进行 polyfill:

wt.datagrams.writable ||= wt.datagrams.createWritable();
// Adds an entry to the event log on the page, optionally applying a specified
// CSS class.

let wt, streamNumber, datagramWriter;

connect.onclick = async () => {
  try {
    const url = document.getElementById('url').value;

    wt = new WebTransport(url);
    wt.datagrams.writable ||= wt.datagrams.createWritable();
    addToEventLog('Initiating connection...');
    await wt.ready;
    addToEventLog(`${(wt.reliability == "reliable-only")? "TCP" : "UDP"} ` +
                  `connection ready.`);
    wt.closed
      .then(() => addToEventLog('Connection closed normally.'))
      .catch(() => addToEventLog('Connection closed abruptly.', 'error'));

    streamNumber = 1;
    datagramWriter = wt.datagrams.writable.getWriter();

    readDatagrams();
    acceptUnidirectionalStreams();
    document.forms.sending.elements.send.disabled = false;
    document.getElementById('connect').disabled = true;
  } catch (e) {
    addToEventLog(`Connection failed. ${e}`, 'error');
  }
}

sendData.onclick = async () => {
  const form = document.forms.sending.elements;
  const data = sending.data.value;
  const bytes = new TextEncoder('utf-8').encode(data);
  try {
    switch (form.sendtype.value) {
      case 'datagram': {
        await datagramWriter.ready;
        datagramWriter.write(bytes).catch(() => {});
        addToEventLog(`Sent datagram: ${data}`);
        break;
      }
      case 'unidi': {
        const writable = await wt.createUnidirectionalStream();
        const writer = writable.getWriter();
        writer.write(bytes).catch(() => {});
        await writer.close();
        addToEventLog(`Sent a unidirectional stream with data: ${data}`);
        break;
      }
      case 'bidi': {
        const duplexStream = await wt.createBidirectionalStream();
        const n = streamNumber++;
        readFromIncomingStream(duplexStream.readable, n);

        const writer = duplexStream.writable.getWriter();
        writer.write(bytes).catch(() => {});
        await writer.close();
        addToEventLog(`Sent bidirectional stream #${n} with data: ${data}`);
        break;
      }
    }
  } catch (e) {
    addToEventLog(`Error while sending data: ${e}`, 'error');
  }
}

// Reads datagrams into the event log until EOF is reached.
async function readDatagrams() {
  try {
    const decoder = new TextDecoderStream('utf-8');

    for await (const data of wt.datagrams.readable.pipeThrough(decoder)) {
      addToEventLog(`Datagram received: ${data}`);
    }
    addToEventLog('Done reading datagrams!');
  } catch (e) {
    addToEventLog(`Error while reading datagrams: ${e}`, 'error');
  }
}

async function acceptUnidirectionalStreams() {
  try {
    for await (const readable of wt.incomingUnidirectionalStreams) {
      const number = streamNumber++;
      addToEventLog(`New incoming unidirectional stream #${number}`);
      readFromIncomingStream(readable, number);
    }
    addToEventLog('Done accepting unidirectional streams!');
  } catch (e) {
    addToEventLog(`Error while accepting streams ${e}`, 'error');
  }
}

async function readFromIncomingStream(readable, number) {
  try {
    const decoder = new TextDecoderStream('utf-8');
    for await (const data of readable.pipeThrough(decoder)) {
      addToEventLog(`Received data on stream #${number}: ${data}`);
    }
    addToEventLog(`Stream #${number} closed`);
  } catch (e) {
    addToEventLog(`Error while reading from stream #${number}: ${e}`, 'error');
    addToEventLog(`    ${e.message}`);
  }
}

function addToEventLog(text, severity = 'info') {
  const log = document.getElementById('event-log');
  const previous = log.lastElementChild;
  const entry = document.createElement('li');
  entry.innerText = text;
  entry.className = `log-${severity}`;
  log.appendChild(entry);

  // If the previous entry in the log was visible, scroll to the new element.
  if (previous &&
      previous.getBoundingClientRect().top < log.getBoundingClientRect().bottom) {
    entry.scrollIntoView();
  }
}

16. 致谢

编辑们感谢工作组主席和团队联系人 Jan-Ivar Bruaroey、Will Law 和 Yves Lafon 的支持。

WebTransport 接口基于最初在 W3C ORTC CG 中描述的 QuicTransport 接口,并已为在本规范中使用而进行了调整。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性参考文献

[CSP3]
Mike West;Antonio Sartori。内容安全策略第 3 级。2026年5月5日。工作草案。网址:https://www.w3.org/TR/CSP3/
[CSS2]
Bert Bos;等。层叠样式表第 2 级修订版 1(CSS 2.1)规范。2011年6月7日。推荐标准。网址:https://www.w3.org/TR/CSS2/
[DOM]
Anne van Kesteren。DOM 标准。现行标准。 网址:https://dom.spec.whatwg.org/
[ECMASCRIPT-6.0]
Allen Wirfs-Brock。ECMA-262 第 6 版,ECMAScript 2015 语言规范。2015年6月。标准。网址:http://www.ecma-international.org/ecma-262/6.0/index.html
[ENCODING]
Anne van Kesteren。编码标准。现行 标准。网址:https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren。Fetch 标准。现行 标准。网址:https://fetch.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss。高精度时间。2026年3月24日。 工作草案。网址:https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren;等。HTML 标准。 现行标准。网址:https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren;Domenic Denicola。Infra 标准。现行标准。网址:https://infra.spec.whatwg.org/
[QUIC]
Jana Iyengar;Martin Thomson。QUIC:一种基于 UDP 的 多路复用安全传输协议。提议标准。网址:https://www.rfc-editor.org/info/rfc9000/
[QUIC-DATAGRAM]
Tommy Pauly;Eric Kinnear;David Schinazi。一种 QUIC 不可靠数据报扩展。提议标准。网址:https://www.rfc-editor.org/info/rfc9221/
[RFC2119]
S. Bradner。用于 RFC 中 指示要求级别的关键词。1997年3月。最佳当前实践。网址:https://datatracker.ietf.org/doc/html/rfc2119
[RFC3279]
L. Bassham;W. Polk;R. Housley。互联网 X.509 公钥基础设施证书和证书吊销 列表(CRL)配置文件的算法与标识符。2002年5月。提议标准。网址:https://www.rfc-editor.org/info/rfc3279/
[RFC5280]
D. Cooper;等。互联网 X.509 公钥 基础设施证书和证书吊销列表(CRL)配置文件。2008年5月。 提议标准。网址:https://www.rfc-editor.org/info/rfc5280/
[RFC8174]
B. Leiba。RFC 2119 关键词中 大写与小写的歧义。2017年5月。最佳当前实践。网址:https://www.rfc-editor.org/info/rfc8174/
[RFC8441]
P. McManus。通过 HTTP/2 引导 WebSocket。2018年9月。提议标准。网址:https://httpwg.org/specs/rfc8441.html
[RFC9002]
J. Iyengar,编;I. Swett,编。QUIC 丢包检测 与拥塞控制。2021年5月。提议标准。网址:https://www.rfc-editor.org/info/rfc9002/
[RFC9220]
R. Hamilton。通过 HTTP/3 引导 WebSocket。2022年6月。提议标准。网址:https://httpwg.org/specs/rfc9220.html
[RFC9525]
P. Saint-Andre;R. Salz。TLS 中的 服务身份。2023年11月。提议标准。网址:https://www.rfc-editor.org/info/rfc9525/
[RFC9846]
E. Rescorla。传输层安全性(TLS) 协议 1.3 版。2026年7月。提议标准。网址:https://www.rfc-editor.org/info/rfc9846/
[STREAMS]
Adam Rice;等。流标准。现行 标准。网址:https://streams.spec.whatwg.org/
[URL]
Anne van Kesteren。URL 标准。现行标准。 网址:https://url.spec.whatwg.org/
[WEB-TRANSPORT-HTTP2]
Alan Frindell;等。基于 HTTP/2 的 WebTransport。互联网草案。网址:https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http2
[WEB-TRANSPORT-HTTP3]
Alan Frindell;Eric Kinnear;Victor Vasiliev。基于 HTTP/3 的 WebTransport。互联网草案。网址:https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3
[WEB-TRANSPORT-OVERVIEW]
Victor Vasiliev。WebTransport 协议 框架。互联网草案。网址:https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-overview
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。现行 标准。网址:https://webidl.spec.whatwg.org/
[WEBSOCKETS]
Adam Rice。WebSocket 标准。现行 标准。网址:https://websockets.spec.whatwg.org/

信息性参考文献

[RELIABLE-RESET]
Marten Seemann; 奥一穂. 带有部分交付的 QUIC 流 重置。Internet-Draft。URL:https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset
[RFC7301]
S. Friedl; 等。传输层安全性(TLS) 应用层协议协商扩展。2014 年 7 月。提议标准。URL:https://www.rfc-editor.org/info/rfc7301/
[RFC9308]
M. Kühlewind; B. Trammell. QUIC 传输协议的 适用性。2022 年 9 月。信息性。URL:https://www.rfc-editor.org/info/rfc9308/
[UNSANCTIONED-TRACKING]
Mark Nottingham. 未经认可的 Web 跟踪。2015 年 7 月 17 日。TAG 结论。URL:https://www.w3.org/2001/tag/doc/unsanctioned-tracking/

IDL 索引

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportDatagramsWritable : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportDatagramDuplexStream {
  WebTransportDatagramsWritable createWritable(
      optional WebTransportSendOptions options = {});
  readonly attribute ReadableStream readable;

  readonly attribute unsigned long maxDatagramSize;
  attribute unrestricted double? incomingMaxAge;
  attribute unrestricted double? outgoingMaxAge;
  attribute unsigned long incomingMaxBufferedDatagrams;
  attribute unsigned long outgoingMaxBufferedDatagrams;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransport {
  constructor(USVString url, optional WebTransportOptions options = {});

  Promise<WebTransportConnectionStats> getStats();
  [NewObject] Promise<Uint8Array> exportKeyingMaterial(BufferSource label, BufferSource context, unsigned long outputLength);
  readonly attribute Promise<undefined> ready;
  readonly attribute WebTransportReliabilityMode reliability;
  readonly attribute WebTransportCongestionControl congestionControl;
  attribute [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams;
  attribute [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams;
  [SameObject] readonly attribute Headers? responseHeaders;
  readonly attribute DOMString protocol;

  readonly attribute Promise<WebTransportCloseInfo> closed;
  readonly attribute Promise<undefined> draining;
  undefined close(optional WebTransportCloseInfo closeInfo = {});

  readonly attribute WebTransportDatagramDuplexStream datagrams;

  Promise<WebTransportBidirectionalStream> createBidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportBidirectionalStream objects */
  readonly attribute ReadableStream incomingBidirectionalStreams;

  Promise<WebTransportSendStream> createUnidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportReceiveStream objects */
  readonly attribute ReadableStream incomingUnidirectionalStreams;
  WebTransportSendGroup createSendGroup();

  static readonly attribute boolean supportsReliableOnly;
};

enum WebTransportReliabilityMode {
  "pending",
  "reliable-only",
  "supports-unreliable",
};

dictionary WebTransportHash {
  required DOMString algorithm;
  required BufferSource value;
};

dictionary WebTransportOptions {
  boolean allowPooling = false;
  boolean requireUnreliable = false;
  HeadersInit headers = {};
  sequence<WebTransportHash> serverCertificateHashes = [];
  WebTransportCongestionControl congestionControl = "default";
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams = null;
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams = null;
  sequence<DOMString> protocols = [];
  ReadableStreamType datagramsReadableType;
};

enum WebTransportCongestionControl {
  "default",
  "throughput",
  "low-latency",
};

dictionary WebTransportCloseInfo {
  unsigned long closeCode = 0;
  USVString reason = "";
};

dictionary WebTransportSendOptions {
  WebTransportSendGroup? sendGroup = null;
  long long sendOrder = 0;
};

dictionary WebTransportSendStreamOptions : WebTransportSendOptions {
  boolean waitUntilAvailable = false;
};

dictionary WebTransportConnectionStats {
  unsigned long long bytesSent;
  unsigned long long bytesSentOverhead;
  unsigned long long bytesAcknowledged;
  unsigned long long packetsSent;
  unsigned long long bytesLost;
  unsigned long long packetsLost;
  unsigned long long bytesReceived;
  unsigned long long packetsReceived;
  DOMHighResTimeStamp smoothedRtt;
  DOMHighResTimeStamp rttVariation;
  DOMHighResTimeStamp minRtt;
  required WebTransportDatagramStats datagrams;
  unsigned long long? estimatedSendRate = null;
  boolean atSendCapacity = false;
};

dictionary WebTransportDatagramStats {
  unsigned long long droppedIncoming;
  unsigned long long expiredIncoming;
  unsigned long long expiredOutgoing;
  unsigned long long lostOutgoing;
};

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportSendStream : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
  Promise<WebTransportSendStreamStats> getStats();
  WebTransportWriter getWriter();
};

dictionary WebTransportSendStreamStats {
  unsigned long long bytesWritten;
  unsigned long long bytesSent;
  unsigned long long bytesAcknowledged;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportSendGroup {
  Promise<WebTransportSendStreamStats> getStats();
};

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportReceiveStream : ReadableStream {
  Promise<WebTransportReceiveStreamStats> getStats();
};

dictionary WebTransportReceiveStreamStats {
  unsigned long long bytesReceived;
  unsigned long long bytesRead;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportBidirectionalStream {
  readonly attribute WebTransportReceiveStream readable;
  readonly attribute WebTransportSendStream writable;
};

[Exposed=*, SecureContext]
interface WebTransportWriter : WritableStreamDefaultWriter {
  Promise<undefined> atomicWrite(optional any chunk);
  undefined commit();
};

[Exposed=(Window,Worker), Serializable, SecureContext]
interface WebTransportError : DOMException {
  constructor(optional DOMString message = "", optional WebTransportErrorOptions options = {});

  readonly attribute WebTransportErrorSource source;
  readonly attribute unsigned long? streamErrorCode;
};

dictionary WebTransportErrorOptions {
  WebTransportErrorSource source = "stream";
  [Clamp] unsigned long? streamErrorCode = null;
};

enum WebTransportErrorSource {
  "stream",
  "session",
};

问题索引

这也需要在 workers 中完成。请参阅 #127whatwg/html#6731

由于在撰写本文时,浏览器中尚未实现针对低延迟进行优化的拥塞控制算法,此配置选项被视为风险特性。

bytesAcknowledgedWebTransportConnectionStats 上已被工作组标识为有实现担忧的风险功能。