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 会话具有以下能力:
要建立与源 origin 以及 protocols 数组的 WebTransport
会话,请按照 [WEB-TRANSPORT-OVERVIEW]
Section
4.1 中的说明,使用 origin,序列化和同构编码后的值作为请求的
`Origin` 头部,并将同构编码后的
protocols 作为客户端希望服务器在此会话中使用的协议列表(按优先级排序),遵循 [WEB-TRANSPORT-OVERVIEW]
Section 3.1
中的描述。建立会话时,客户端不得提供任何凭据。生成的底层传输流称为会话的CONNECT 流。
当服务器请求CONNECT 流优雅关闭时,WebTransport 会话 session处于排空状态,详见[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] Section 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]]
| 拥有此 WebTransportDatagramsWritable 的一个
WebTransport。
|
[[SendGroup]]
| 一个可选的 WebTransportSendGroup,或者为 null。
|
[[SendOrder]]
| 一个可选的发送顺序号,默认为 0。 |
要创建一个
WebTransportDatagramsWritable,给定一个
WebTransport
transport,一个
sendGroup,以及一个 sendOrder,请执行以下步骤。
-
设 stream 为一个 新的
WebTransportDatagramsWritable,具有:[[OutgoingDatagramsQueue]]-
一个空队列
[[Transport]]-
transport
[[SendGroup]]-
sendGroup
[[SendOrder]]-
sendOrder
-
设 writeDatagramsAlgorithm 为一个运行 writeDatagrams,参数为 transport 和 stream 的操作。
-
设置 stream,其中 writeAlgorithm 设置为 writeDatagramsAlgorithm。
-
返回 stream。
4.2. 属性
sendGroup, 类型为 WebTransportSendGroup, 可空-
getter 步骤:
-
返回 this 的
[[SendGroup]]。
setter 步骤,给定 value:
-
如果 value 非空,且 value.
[[Transport]]不是 this.[[Transport]],抛出一个InvalidStateError。 -
设置 this.
[[SendGroup]]为 value。
-
sendOrder, 类型为 long long-
getter 步骤:
-
返回 this 的
[[SendOrder]]。
setter 步骤,给定 value:
-
设置 this.
[[SendOrder]]为 value。
-
4.3. 过程
writeDatagrams 算法给定一个 transport 和 writable 作为参数,以及 data 作为输入。它通过运行以下步骤来定义:
-
设 timestamp 为一个表示当前时间的 timestamp。
-
如果 data 不是一个
BufferSource对象,则返回 一个 promise 被拒绝,并返回一个TypeError。 -
设 datagrams 为 transport.
[[Datagrams]]。 -
如果 datagrams.
[[OutgoingMaxDatagramSize]]小于 data 的 [[ByteLength]],则返回 一个 promise 被解析,并返回 undefined。 -
设 promise 为一个新的 promise。
-
设 bytes 为 data 表示的字节的副本。
-
设 chunk 为一个元组,包含 bytes、timestamp 和 promise。
-
将 chunk 入队到 writable.
[[OutgoingDatagramsQueue]]。 -
如果 writable.
[[OutgoingDatagramsQueue]]的长度小于 datagrams.[[OutgoingDatagramsHighWaterMark]],则解析 promise 并返回 undefined。 -
返回 promise。
注意: 关联的 WritableStream 仅当该流的 writeDatagrams 返回的所有 promise 都已解析时,才会调用 writeDatagrams。因此,只有当
Web
开发人员关注 WritableStreamDefaultWriter.ready 时,时间戳和过期持续时间才能很好地工作。
要 sendDatagrams,给定一个
WebTransport 对象
transport 和一个 WebTransportDatagramsWritable 对象
writable,将一个网络任务入队,使用 transport 运行以下步骤:
-
设 queue 为 writable.
[[OutgoingDatagramsQueue]]的副本。注意: 上述副本以及将网络任务排队以运行这些步骤都可以进行优化。
-
设 maxSize 为 transport.
[[Datagrams]].[[OutgoingMaxDatagramSize]]。 -
设 duration 为 transport.
[[Datagrams]].[[OutgoingDatagramsExpirationDuration]]。 -
如果 duration 为 null,则将 duration 设置为一个 实现定义的值。
-
并行运行以下步骤:
-
当 queue 不为空时:
-
如果 transport.
[[State]]不是"connected",则返回。 -
当 queue 不为空时:
-
设 bytes、timestamp 和 promise 为 queue 的第一个元素。
-
如果 bytes 的长度 ≤ maxSize:
-
如果无法立即将 bytes 发送到网络,则跳出此循环。
-
发送一个数据报,使用 transport.
[[Session]]和 bytes。
-
-
从 queue 中移除第一个元素。
-
-
对于任何 WebTransport 对象,用户代理必须:其
[[State]] 为 "connecting" 或
"connected",在与其关联的 WebTransportDatagramsWritable 对象的子集(由 发送顺序规则确定)上运行 sendDatagrams,并且只要算法能够取得进展,就应尽快执行此操作。
发送顺序规则是,通常,发送可能与先前排队的流和数据报的发送交错进行,以及尚未排队以通过此传输发送的流和数据报,但发送必须暂停,直到所有在具有相同
[[SendGroup]]
和更高
[[SendOrder]]
的流和数据报上排队等待发送的字节,这些流和数据报既没有 出错,也没有被 流量控制阻止,已经被发送。
注意: 允许在传输的 [[State]]
为 "connecting" 时写入数据报。数据报存储在
[[OutgoingDatagramsQueue]]
中,并且可以像在 "connected" 状态下一样丢弃它们。一旦传输的 [[State]] 变为 "connected",它将开始发送排队的数据报。
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 unrestricted double incomingHighWaterMark ;attribute unrestricted double outgoingHighWaterMark ; };
5.1. 内部插槽
一个 WebTransportDatagramDuplexStream 对象具有以下内部插槽。
| 内部槽 | 描述(非规范性) |
|---|---|
[[Readable]]
| 用于接收数据报的 ReadableStream。
|
[[ReadableMode]]
| 接收数据报时使用的 DatagramsReadableMode。
|
[[Writables]]
| 一个由 WebTransportDatagramsWritable
流组成的有序集合,初始为空。
|
[[IncomingDatagramsQueue]]
| 由接收数据报与时间戳组成的队列。 |
[[IncomingDatagramsPullPromise]]
| 由 pullDatagrams 设置的 promise,用于等待接收数据报。 |
[[IncomingDatagramsHighWaterMark]]
| 一个 unrestricted double
,表示接收数据报的
高水位线。
|
[[IncomingDatagramsExpirationDuration]]
| 一个 unrestricted double
,表示接收数据报的过期时间(毫秒),或为 null。
|
[[OutgoingDatagramsHighWaterMark]]
| 一个 unrestricted double
,表示发送数据报的
高水位线。
|
[[OutgoingDatagramsExpirationDuration]]
| 一个 unrestricted double
,表示发送数据报的过期时间(毫秒),或为 null。
|
[[OutgoingMaxDatagramSize]]
|
一个整数,表示发送数据报的最大尺寸。
最大数据报大小取决于所使用的协议。
在 HTTP/3 [WEB-TRANSPORT-HTTP3] 中,该值与路径 MTU 的估算有关,
并会因实现定义的开销而适当减少。
在 HTTP/2 [WEB-TRANSPORT-HTTP2] 中则没有类似限制。
由于数据报处理通常会将整个数据报保存在内存中,实际实现会对大小有限制。 未来的协议扩展可以实现对所有协议变体的数据报大小限制进行信号通知。 |
用户代理 MAY 可为任何 WebTransport
对象更新 [[OutgoingMaxDatagramSize]]
,只要其
[[State]]
为 "connecting" 或 "connected"。
要创建一个
WebTransportDatagramDuplexStream
,给定
readable 和
readableMode,
执行以下步骤。
-
令 stream 为 新建的
WebTransportDatagramDuplexStream,属性如下:[[Readable]]-
readable
[[ReadableMode]]-
readableMode
[[Writables]]-
一个空的有序集合。
[[IncomingDatagramsQueue]]-
一个空队列
[[IncomingDatagramsPullPromise]]-
null
[[IncomingDatagramsHighWaterMark]]-
一个实现定义值
[[IncomingDatagramsExpirationDuration]]-
null
[[OutgoingDatagramsHighWaterMark]]-
一个实现定义值
该实现定义值应当调优以确保合理的吞吐率,同时不影响数据传输的及时性。
[[OutgoingDatagramsExpirationDuration]]-
null
[[OutgoingMaxDatagramSize]]-
一个实现定义整数。
-
返回 stream。
5.2. 方法
createWritable()-
创建一个
WebTransportDatagramsWritable。当调用
createWritable()方法时,用户代理必须运行以下步骤:-
设 transport 为与 this 关联的
WebTransport对象。 -
如果 transport.
[[State]]为"closed"或"failed",抛出一个InvalidStateError。 -
返回使用 transport、sendGroup 和 sendOrder 创建一个
WebTransportDatagramsWritable的结果。
-
5.3. 属性
readable, 类型为 ReadableStream, readonly-
getter 步骤:
-
返回 this.
[[Readable]]。
-
incomingMaxAge, 类型为 unrestricted double, nullable-
getter 步骤:
setter 步骤,给定 value:
-
如果 value 为负数或 NaN,抛出一个
RangeError。 -
如果 value 为
0,设置 value 为 null。 -
设置 this.
[[IncomingDatagramsExpirationDuration]]为 value。
maxDatagramSize, 类型为 unsigned long, readonly-
可以传递给
WebTransportDatagramsWritable的最大大小数据。 getter 步骤是返回 this.[[OutgoingMaxDatagramSize]]。 outgoingMaxAge, 类型为 unrestricted double, nullable-
getter 步骤:
setter 步骤,给定 value:
-
如果 value 为负数或 NaN,抛出一个
RangeError。 -
如果 value 为
0,设置 value 为 null。 -
设置 this.
[[OutgoingDatagramsExpirationDuration]]为 value。
incomingHighWaterMark, 类型为 unrestricted double-
getter 步骤:
setter 步骤,给定 value:
-
如果 value 为负数或 NaN,抛出一个
RangeError。 -
如果 value <
1,设置 value 为1。 -
设置 this.
[[IncomingDatagramsHighWaterMark]]为 value。
outgoingHighWaterMark, 类型为 unrestricted double-
getter 步骤:
setter 步骤,给定 value:
-
如果 value 为负数或 NaN,抛出一个
RangeError。 -
如果 value <
1,设置 value 为1。 -
设置 this.
[[OutgoingDatagramsHighWaterMark]]为 value。
5.4. 过程
要 pullDatagrams,给定一个
WebTransport 对象
transport,运行以下步骤:
-
令 datagrams 为 transport.
[[Datagrams]]。 -
断言:datagrams.
[[IncomingDatagramsPullPromise]]为 null。 -
令 queue 为 datagrams.
[[IncomingDatagramsQueue]]。 -
如果 queue 为空,则:
-
将 datagrams.
[[IncomingDatagramsPullPromise]]设为一个新的 promise。 -
返回 datagrams.
[[IncomingDatagramsPullPromise]]。
-
-
令 datagram 和 timestamp 为 出队 queue 的结果。
-
如果 datagrams.
[[ReadableMode]]为"bytes",则:-
如果 datagrams.
[[Readable]]的 当前 BYOB 请求视图不为 null,则:-
令 view 为 datagrams.
[[Readable]]的 当前 BYOB 请求视图。 -
如果 view 的 字节长度小于 datagram 的大小,返回 一个被拒绝的 promise,错误为
RangeError。 -
令 elementSize 为 类型化数组构造表中 view.[[TypedArrayName]] 指定的元素大小。如果 view 没有 [[TypedArrayName]] 内部槽(即它是
DataView),则令 elementSize 为 0。 -
如果 elementSize 不为 1,返回 一个被拒绝的 promise,错误为
TypeError。
-
-
从字节中拉取 datagram 到 datagrams.
[[Readable]]。
-
-
否则:
-
令 chunk 为一个新的
Uint8Array对象,表示 datagram。 -
入队 chunk 到 transport.
[[Datagrams]].[[Readable]]。
-
-
返回 一个已解决的 promise,值为 undefined。
要receiveDatagrams,给定一个
WebTransport
对象 transport,运行以下步骤:
-
令 timestamp 为当前时间的时间戳。
-
令 queue 为 datagrams.
[[IncomingDatagramsQueue]]。 -
令 duration 为 datagrams.
[[IncomingDatagramsExpirationDuration]]。 -
如果 duration 为 null,则将 duration 设为一个 实现定义的值。
-
令 session 为 transport.
[[Session]]。 -
当 session 上有 可用的接收数据报时:
-
令 toBeRemoved 为 queue 的长度减去 datagrams.
[[IncomingDatagramsHighWaterMark]]。 -
当 queue 不为空时:
-
如果 queue 不为空且 datagrams.
[[IncomingDatagramsPullPromise]]非 null,则:-
令 bytes 和 timestamp 为 出队 queue 的结果。
-
令 promise 为 datagrams.
[[IncomingDatagramsPullPromise]]。 -
将 datagrams.
[[IncomingDatagramsPullPromise]]设为 null。 -
队列一个网络任务,参数为 transport,执行以下步骤:
-
令 chunk 为一个新的
Uint8Array对象,表示 bytes。 -
入队 chunk 到 datagrams.
[[Readable]]。 -
解决 promise,值为 undefined。
-
-
用户代理 SHOULD 在任何 WebTransport
对象的
[[State]]
为 "connected" 时,只要该算法可以推进,应尽快运行 receiveDatagrams。
6. WebTransport 接口
WebTransport 提供了一个 API,用于访问 [WEB-TRANSPORT-OVERVIEW] 中定义的底层传输功能。
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransport (constructor USVString ,url optional WebTransportOptions = {});options Promise <WebTransportConnectionStats >getStats (); [NewObject ]Promise <ArrayBuffer >exportKeyingMaterial (BufferSource ,label optional BufferSource );context readonly attribute Promise <undefined >ready ;readonly attribute WebTransportReliabilityMode reliability ;readonly attribute WebTransportCongestionControl congestionControl ; [EnforceRange ]attribute unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams ; [EnforceRange ]attribute unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams ;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 = {}); /* a ReadableStream of WebTransportBidirectionalStream objects */options readonly attribute ReadableStream incomingBidirectionalStreams ;Promise <WebTransportSendStream >createUnidirectionalStream (optional WebTransportSendStreamOptions = {}); /* a ReadableStream of WebTransportReceiveStream objects */options readonly attribute ReadableStream incomingUnidirectionalStreams ;WebTransportSendGroup createSendGroup ();static readonly attribute boolean supportsReliableOnly ; };enum {WebTransportReliabilityMode ,"pending" ,"reliable-only" , };"supports-unreliable"
6.1. 内部插槽
一个 WebTransport 对象具有以下内部插槽。
| 内部插槽 | 描述 (非规范性) |
|---|---|
[[SendStreams]]
| 此 WebTransport 拥有的一个
WebTransportSendStream
的有序集合。
|
[[ReceiveStreams]]
| 此 WebTransport 拥有的一个 WebTransportReceiveStream 的有序集合。
|
[[IncomingBidirectionalStreams]]
| 一个由 WebTransportBidirectionalStream 对象组成的
ReadableStream。
|
[[IncomingUnidirectionalStreams]]
| 一个由 WebTransportReceiveStream 组成的 ReadableStream。
|
[[State]]
| 一个枚举,指示传输的状态。为
"connecting"、"connected"、"draining"、"closed"
和 "failed" 之一。
|
[[Ready]]
| 当关联的 WebTransport 会话 建立时,此 promise 会被实现;如果建立过程失败,则此 promise 会被拒绝。 |
[[Reliability]]
| 一个
WebTransportReliabilityMode,指示第一跳是否支持不可靠的
(UDP) 传输,或者是否仅支持可靠的 (TCP 回退) 传输。在建立连接之前,返回 "pending"。
|
[[CongestionControl]]
| 一个
WebTransportCongestionControl,指示应用程序是否请求了针对吞吐量或低延迟优化的拥塞控制算法的偏好,并且该偏好是否已由用户代理满足;或者
"default"。
|
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]
| 应用程序预计服务器将创建的并发打开的入向单向流的数量,或者为 null。 |
[[AnticipatedConcurrentIncomingBidirectionalStreams]]
| 应用程序预计服务器将创建的并发打开的双向流的数量,或者为 null。 |
[[Protocol]]
| 一个字符串,指示服务器选择的应用程序级协议(如果有)。最初为空字符串。 |
[[Closed]]
| 当关联的 WebTransport 对象正常关闭时,此 promise
会被实现;当其突然关闭或在初始化时失败时,此
promise 会被拒绝。
|
[[Draining]]
| 当关联的 WebTransport 会话 耗尽时,此 promise 会被实现。 |
[[Datagrams]]
| 一个 WebTransportDatagramDuplexStream。
|
[[Session]]
| 此 WebTransport 对象的WebTransport
会话,或者为 null。
|
6.2. 构造函数
WebTransport()
构造函数时,用户代理必须运行以下步骤:
-
令 baseURL 为 this 的 相关设置对象的 API 基础 URL。
-
如果 parsedURL 为失败,则 抛出
SyntaxError异常。 -
如果 parsedURL 的 scheme 不是
https,则 抛出SyntaxError异常。 -
如果 parsedURL 的 fragment 不为 null,则 抛出
SyntaxError异常。 -
令 allowPooling 为
options的allowPooling。 -
令 dedicated 为 allowPooling 的取反值。
-
令 serverCertificateHashes 为
options的serverCertificateHashes(如果存在),否则为 null。 -
如果 dedicated 为 false 且 serverCertificateHashes 非 null,则 抛出
NotSupportedError异常。 -
令 requireUnreliable 为
options的requireUnreliable。 -
令 congestionControl 为
options的congestionControl。 -
如果 congestionControl 不为
"default"且用户代理不支持任何针对 congestionControl 优化的拥塞控制算法(参见 [RFC9002] 第7节),则将 congestionControl 设为"default"。 -
如果 protocols 中的任意值出现超过一次、未能匹配 WebTransport 协议定义的协商应用协议的元素要求、或其 同构编码长度为0或超过512,则 抛出
SyntaxError异常。 [WEB-TRANSPORT-OVERVIEW] 第3.1节。 -
令 anticipatedConcurrentIncomingUnidirectionalStreams 为
options的anticipatedConcurrentIncomingUnidirectionalStreams。 -
令 anticipatedConcurrentIncomingBidirectionalStreams 为
options的anticipatedConcurrentIncomingBidirectionalStreams。 -
令 datagramsReadableMode 为
options的datagramsReadableMode。 -
令 incomingDatagrams 为一个 新建的
ReadableStream。 -
令 datagrams 为 创建
WebTransportDatagramDuplexStream的结果,readable 设为 incomingDatagrams,readableMode 设为 datagramsReadableMode。 -
令 transport 为新构造的
WebTransport对象,属性如下:[[SendStreams]]-
一个空的 有序集合
[[ReceiveStreams]]-
一个空的 有序集合
[[IncomingBidirectionalStreams]]-
一个新的
ReadableStream [[IncomingUnidirectionalStreams]]-
一个新的
ReadableStream [[State]]-
"connecting" [[Ready]]-
一个新的 promise
[[Reliability]]-
"pending"
[[CongestionControl]]-
congestionControl
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]-
anticipatedConcurrentIncomingUnidirectionalStreams
[[AnticipatedConcurrentIncomingBidirectionalStreams]]-
anticipatedConcurrentIncomingBidirectionalStreams
[[Protocol]]-
一个空字符串
[[Closed]]-
一个新的 promise
[[Draining]]-
一个新的 promise
[[Datagrams]]-
datagrams
[[Session]]-
null
-
令 pullDatagramsAlgorithm 为一个运行 pullDatagrams,参数为 transport 的动作。
注意: 建议数据报使用 64kB 的缓冲区,因为 WebTransport 数据报帧有效最大值受 QUIC 最大数据报帧的上限影响,建议为 64kB(参见 [QUIC-DATAGRAM] 第3节)。 这样可以确保流不会因数据报大于缓冲区而出错。
-
如果 datagramsReadableMode 为
"bytes",则 以字节读取支持方式 设置 incomingDatagrams,pullAlgorithm 设为 pullDatagramsAlgorithm,highWaterMark 设为 0。否则,设置 incomingDatagrams,pullAlgorithm 设为 pullDatagramsAlgorithm, highWaterMark 设为 0。 -
令 pullBidirectionalStreamAlgorithm 为一个运行 pullBidirectionalStream,参数为 transport 的动作。
-
设置 transport.
[[IncomingBidirectionalStreams]],pullAlgorithm 设为 pullBidirectionalStreamAlgorithm, highWaterMark 设为 0。 -
令 pullUnidirectionalStreamAlgorithm 为一个运行 pullUnidirectionalStream,参数为 transport 的动作。
-
设置 transport.
[[IncomingUnidirectionalStreams]],pullAlgorithm 设为 pullUnidirectionalStreamAlgorithm, highWaterMark 设为 0。 -
初始化 WebTransport over HTTP,参数为 transport, parsedURL, dedicated, requireUnreliable, congestionControl, protocols, serverCertificateHashes。
-
返回 transport。
WebTransport
对象 transport、URL 记录 url、布尔值 dedicated、布尔值
requireUnreliable、WebTransportCongestionControl
congestionControl、数组 protocols 和
序列 WebTransportHash
serverCertificateHashes,运行以下步骤。
-
令 client 为 transport 的 相关设置对象。
-
令 origin 为 client 的 origin。
-
令 request 为一个新的 请求,其 URL 为 url,client 为 client,policy container 为 client 的 policy container,destination 为空字符串, origin 为 origin,redirect mode 为 "error"。
-
如果 内容安全策略应阻止请求?,参数为 request 返回 "Blocked",或 request 因端口不合法应被阻止 返回 blocked,则终止剩余步骤并 队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
令 error 为新 创建 的
WebTransportError,其source为"session"。 -
清理 transport,参数为 error。
-
-
运行以下步骤 并行,但当 transport.
[[State]]变为"closed"或"failed"时 终止:-
令 newConnection 为 "
no",如果 dedicated 为 false;否则为 "yes-and-dedicated"。 -
令 connection 为用 networkPartitionKey、url、false、newConnection 和 requireUnreliable 获取连接的结果。如果用户代理支持多种拥塞控制算法,选择适合 congestionControl 的算法用于该连接的数据发送。当获取连接时, 如果指定了 serverCertificateHashes,则不采用默认证书验证算法,只要满足 自定义证书要求且 证书哈希校验对 serverCertificateHashes 返回 true,则证书有效,否则 connection 为失败。
-
如果 connection 为失败,则终止剩余步骤并 队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
令 error 为新 创建的
WebTransportError,其source为"session"。 -
清理 transport,参数为 error。
注意: 不跟随重定向。由于重定向导致的网络错误与其他网络错误不可区分。在跨域环境下,这会暴露通常被 CORS 阻止的信息。在同源环境下,则可能鼓励应用滥用握手作为信息传递渠道。
-
-
等待 connection 接收第一个 SETTINGS 帧,并令 settings 为表示该 SETTINGS 帧的字典。
-
如果 settings 未包含 SETTINGS_ENABLE_WEBTRANPORT 且值为 1,或未包含 H3_DATAGRAM 且值为 1,则终止剩余步骤并 队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
令 error 为新 创建 的
WebTransportError,其source为"session"。 -
清理 transport,参数为 error。
-
-
建立一个 WebTransport 会话,参数为 origin 和 protocols,在 connection 上。
注意: 此步骤还包含 [QUIC-DATAGRAM] 规定的传输参数交换。
-
如果上一步失败,则终止剩余步骤并 队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
令 error 为新 创建 的
WebTransportError,其source为"session"。 -
清理 transport,参数为 error。
-
-
令 session 为已建立的 WebTransport 会话。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
断言:this 的
[[Datagrams]]的[[OutgoingMaxDatagramSize]]是整数。 -
如果 transport.
[[State]]不为"connecting": -
设置 transport.
[[State]]为"connected"。 -
设置 transport.
[[Session]]为 session。 -
设置 transport.
[[Protocol]]为协商应用协议的字符串值(如有),参见 [WEB-TRANSPORT-OVERVIEW] 第3.1节,否则为""。 -
如果连接为 HTTP/3,则设置 transport.
[[Reliability]]为"supports-unreliable"。 -
如果连接为 HTTP/2 [WEB-TRANSPORT-HTTP2],则设置 transport 的
[[Reliability]]为"reliable-only"。
-
-
WebTransport
对象 transport,运行以下步骤:
-
如果 transport.
[[State]]为"connecting",则在 transport.[[Ready]]实现时,返回以下步骤的结果:-
返回 pullBidirectionalStream,参数为 transport 的结果。
-
-
如果 transport.
[[State]]不为"connected",则返回一个新的 拒绝的 promise,错误为InvalidStateError。 -
令 session 为 transport.
[[Session]]。 -
令 p 为一个新的 promise。
-
并行运行以下步骤:
-
等待 session 中有 可用的入向双向流。
-
令 internalStream 为 接收双向流,参数为 session 的结果。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
令 stream 为 创建
WebTransportBidirectionalStream,参数为 internalStream 和 transport 的结果。 -
入队 stream 到 transport.
[[IncomingBidirectionalStreams]]。 -
解决 p,值为 undefined。
-
-
-
返回 p。
WebTransport
对象 transport,运行以下步骤:
-
如果 transport.
[[State]]为"connecting",则在 transport.[[Ready]]实现时,返回以下步骤的结果:-
返回 pullUnidirectionalStream,参数为 transport 的结果。
-
-
如果 transport.
[[State]]不为"connected",则返回一个新的 拒绝的 promise,错误为InvalidStateError。 -
令 session 为 transport.
[[Session]]。 -
令 p 为一个新的 promise。
-
并行运行以下步骤:
-
等待 session 中有 可用的入向单向流。
-
令 internalStream 为 接收入向单向流,参数为 session 的结果。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
令 stream 为 创建
WebTransportReceiveStream,参数为 internalStream 和 transport 的结果。 -
入队 stream 到 transport.
[[IncomingUnidirectionalStreams]]。 -
解决 p,值为 undefined。
-
-
-
返回 p。
6.3. 属性
ready,类型为 Promise<undefined>,只读closed,类型为 Promise<WebTransportCloseInfo>,只读-
获取时,必须返回 this 的
[[Closed]]。 draining,类型为 Promise<undefined>,只读-
获取时,必须返回 this 的
[[Draining]]。 datagrams,类型为 WebTransportDatagramDuplexStream, 只读-
用于该会话中发送和接收数据报的单一双工流。
datagrams属性的 getter 步骤如下:-
返回 this 的
[[Datagrams]]。
-
incomingBidirectionalStreams, 类型为 ReadableStream,只读-
返回一个
ReadableStream, 其中包含已从服务器接收的WebTransportBidirectionalStream。注意: 入向流是否已有数据,取决于服务器行为。
incomingBidirectionalStreams属性的 getter 步骤如下: incomingUnidirectionalStreams, 类型为 ReadableStream,只读-
一个
ReadableStream,其中每个流由WebTransportReceiveStream表示, 均为从服务器接收的单向流。注意: 入向流是否已有数据,取决于服务器行为。
incomingUnidirectionalStreams属性的 getter 步骤如下: 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。
注意: 设置 anticipatedConcurrentIncomingUnidirectionalStreams
或
anticipatedConcurrentIncomingBidirectionalStreams
并不保证应用会收到预期数量的流。
protocol,类型为 DOMString,只读-
当 WebTransport 会话已经建立,并且构造函数的
protocols选项提供了非空数组时,返回服务器选定的应用级协议(如有);否则返回空字符串。 getter 步骤为返回 this 的[[Protocol]]。
6.4. 方法
close(closeInfo)-
终止与该 WebTransport 对象关联的 WebTransport 会话。
调用 close 时,用户代理必须运行以下步骤:
-
令 transport 为 this。
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
如果 transport.
[[State]]为"connecting":-
令 error 为新 创建 的
WebTransportError, 其source为"session"。 -
清理 transport,参数为 error。
-
终止这些步骤。
-
-
令 session 为 transport.
[[Session]]。 -
令 code 为 closeInfo.
closeCode。 -
令 reasonString 为 closeInfo.
reason的最大 码元前缀,使得该前缀 长度(UTF-8 编码)不超过 1024。 -
令 reason 为 reasonString 的 UTF-8 编码值。
-
并行,终止 session,参数为 code 和 reason。
注意:这也会 中止发送或 中止接收 transport.
[[SendStreams]]和[[ReceiveStreams]]中包含的 WebTransport 流。 -
清理 transport,参数为
AbortError和 closeInfo。
-
getStats()-
收集该
WebTransport的 底层连接的统计信息, 并异步返回结果。调用 getStats 时,用户代理必须运行以下步骤:
-
令 transport 为 this。
-
令 p 为一个新的 promise。
-
如果 transport.
[[State]]为"failed",则 拒绝 p,错误为InvalidStateError,并终止这些步骤。 -
并行运行以下步骤:
-
如果 transport.
[[State]]为"connecting",则等待状态改变。 -
如果 transport.
[[State]]为"failed",则在 队列一个网络任务(参数为 transport)后, 拒绝 p,错误为InvalidStateError,并终止这些步骤。 -
如果 transport.
[[State]]为"closed",则在 队列一个网络任务(参数为 transport)后, 解决 p, 值为连接最近可用的统计信息。统计信息收集的具体时点为 实现定义。 -
收集 底层连接的统计信息,包括数据报的统计。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
令 stats 为一个新的 new
WebTransportConnectionStats对象,表示收集到的统计信息。 -
解决 p,值为 stats。
-
-
-
返回 p。
-
exportKeyingMaterial(BufferSource label, optional BufferSource context)-
从与该
WebTransport底层连接 唯一关联的 TLS 会话中导出密钥材料,使用 TLS Keying Material Exporter。调用
exportKeyingMaterial时,用户代理必须运行以下步骤:-
令 transport 为 this。
-
令 labelLength 为 label 的 字节长度。
-
如果 labelLength 超过 255,返回 一个被拒绝的 promise,错误为
RangeError。 -
令 contextLength 为 0。
-
如果 context 被给定,则将 contextLength 设为 context 的 字节长度。
-
如果 contextLength 超过 255,返回 一个被拒绝的 promise,错误为
RangeError。 -
令 p 为一个新的 promise。
-
并行运行以下步骤,但当 transport 的
[[State]]变为"closed"或"failed"时终止,并改为 队列一个网络任务,参数为 transport,拒绝 p,错误为InvalidStateError:-
令 keyingMaterial 为导出 TLS 密钥材料的结果,如 [WEB-TRANSPORT-OVERVIEW] 第 4.1 节 所定义, 使用 labelLength、label、contextLength 以及(如有)context。
-
-
返回 p。
-
createBidirectionalStream()-
创建一个用于出向双向流的
WebTransportBidirectionalStream对象。注意,仅创建流并不会立即让对端可见,只有发送数据后才会被对端感知。注意:服务器在数据发送前不会感知流的创建。
调用
createBidirectionalStream时,用户代理必须运行以下步骤:-
令 transport 为 this。
-
如果 transport.
[[State]]为"closed"或"failed",返回一个新的 被拒绝的 promise,错误为InvalidStateError。 -
令 waitUntilAvailable 为
options的waitUntilAvailable。 -
令 p 为一个新的 promise。
-
并行运行以下步骤,但当 transport 的
[[State]]变为"closed"或"failed"时终止,并改为 队列一个网络任务,参数为 transport,拒绝 p,错误为InvalidStateError:-
令 streamId 为一个新的流 ID,对 transport.
[[Session]]有效且唯一,定义见 [QUIC] 第 19.11 节。如因耗尽未能立即获得流 ID,若 waitUntilAvailable 为 true,则等待可用;否则为 false 时,队列一个网络任务,参数为 transport,拒绝 p,错误为QuotaExceededError,并终止这些步骤。 -
令 internalStream 为 创建双向流的结果,参数为 transport.
[[Session]]和 streamId。 -
队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed", 拒绝 p,错误为InvalidStateError,并终止这些步骤。 -
令 stream 为 创建
WebTransportBidirectionalStream的结果,参数为 internalStream、transport、sendGroup 和 sendOrder。 -
解决 p,值为 stream。
-
-
-
返回 p。
-
createUnidirectionalStream()-
创建一个用于出向单向流的
WebTransportSendStream对象。注意,仅创建流并不会立即让服务器可见,只有发送数据后才会被服务器感知。注意:服务器在数据发送前不会感知流的创建。
调用
createUnidirectionalStream()方法时,用户代理必须运行以下步骤:-
令 transport 为 this。
-
如果 transport.
[[State]]为"closed"或"failed",返回一个新的 被拒绝的 promise,错误为InvalidStateError。 -
令 waitUntilAvailable 为
options的waitUntilAvailable。 -
令 p 为一个新的 promise。
-
并行运行以下步骤,但当 transport 的
[[State]]变为"closed"或"failed"时终止,并改为 队列一个网络任务,参数为 transport,拒绝 p,错误为InvalidStateError:-
令 streamId 为一个新的流 ID,对 transport.
[[Session]]有效且唯一,定义见 [QUIC] 第 19.11 节。如因耗尽未能立即获得流 ID,若 waitUntilAvailable 为 true,则等待可用;否则为 false 时,队列一个网络任务,参数为 transport,拒绝 p,错误为QuotaExceededError,并终止这些步骤。 -
令 internalStream 为 创建出向单向流的结果,参数为 transport.
[[Session]]和 streamId。 -
队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed", 拒绝 p,错误为InvalidStateError,并终止这些步骤。 -
令 stream 为 创建
WebTransportSendStream的结果,参数为 internalStream、transport、sendGroup 和 sendOrder。 -
解决 p,值为 stream。
-
-
-
返回 p。
-
createSendGroup()-
创建一个
WebTransportSendGroup。调用
createSendGroup()方法时,用户代理必须运行以下步骤:-
令 transport 为 this。
-
如果 transport.
[[State]]为"closed"或"failed", 抛出InvalidStateError。 -
返回 创建
WebTransportSendGroup的结果,参数为 transport。
-
6.5. 过程
WebTransport
transport,参数为 error,以及可选的 closeInfo,请执行以下步骤:
-
令 sendStreams 为 transport.
[[SendStreams]]的一个副本。 -
令 receiveStreams 为 transport.
[[ReceiveStreams]]的一个副本。 -
令 outgoingDatagramWritables 为 transport.
[[Datagrams]].[[Writables]]。 -
令 incomingDatagrams 为 transport.
[[Datagrams]].[[Readable]]。 -
令 ready 为 transport.
[[Ready]]。 -
令 closed 为 transport.
[[Closed]]。 -
令 incomingBidirectionalStreams 为 transport.
[[IncomingBidirectionalStreams]]。 -
令 incomingUnidirectionalStreams 为 transport.
[[IncomingUnidirectionalStreams]]。 -
将 transport.
[[SendStreams]]设为空集合。 -
将 transport.
[[ReceiveStreams]]设为空集合。 -
将 transport.
[[Datagrams]].[[OutgoingDatagramsQueue]]设为空队列。 -
将 transport.
[[Datagrams]].[[IncomingDatagramsQueue]]设为空队列。 -
如果给定了 closeInfo,将 transport.
[[State]]设为"closed"; 否则,将 transport.[[State]]设为"failed"。 -
遍历 sendStreams 中的每个 stream,执行:
-
如果 stream.
[[PendingOperation]]不为 null,则拒绝 stream.[[PendingOperation]],原因为 error。 -
报错 stream,错误为 error。
-
-
遍历 receiveStreams 中的每个 stream,报错 stream,错误为 error。
注意:脚本作者可在 Promise 解决时注入同步代码。因此,从这里开始不要再操作 transport,因为脚本可能以不可预测方式更改其状态。调用此过程的逻辑也应如此。
-
如果给定了 closeInfo,则:
-
否则:
-
拒绝 closed,原因为 error。
-
设置 closed.
[[PromiseIsHandled]]为 true。 -
拒绝 ready,原因为 error。
-
设置 ready.
[[PromiseIsHandled]]为 true。 -
报错 incomingBidirectionalStreams,错误为 error。
-
报错 incomingUnidirectionalStreams,错误为 error。
-
遍历 outgoingDatagramWritables 中的每个 writable,报错 writable,错误为 error。
-
报错 incomingDatagrams,错误为 error。
-
要队列一个网络任务,参数为 WebTransport
transport 和一系列步骤 steps,请执行以下步骤:
6.6. 并非由客户端发起的会话终止
WebTransport
transport 关联的 WebTransport 会话
使用可选的 code 和 reasonBytes 终止时,运行以下步骤:
-
将网络任务排队到 transport 以运行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",中止这些步骤。 -
设 error 为新 创建的
WebTransportError,其source为"session"。 -
设 closeInfo 为一个 新的
WebTransportCloseInfo。 -
如果给定了 code,则将 closeInfo 的
closeCode设置为 code。 -
如果给定了 reasonBytes,则将 closeInfo 的
reason设置为 reasonBytes, UTF-8 解码。注意: 没有语言或方向 元数据可用于 reasonBytes。 First-strong 启发式方法可以用于 显示该值时的方向。
-
清理 transport,使用 error 和 closeInfo。
-
WebTransport
transport 的 底层连接出现连接错误时,
运行以下步骤:
6.7. 上下文清理步骤
本规范定义了上下文清理步骤,作为给定
WebTransport
transport 的以下步骤:
-
如果 transport.
[[State]]为"connected",则:-
将 transport.
[[State]]设置为"failed"。 -
并行,终止 transport.
[[Session]]。 -
将网络任务排队到 transport 以运行以下步骤:
-
设 error 为新 创建的
WebTransportError,其source为"session"。 -
清理 transport,使用 error。
-
-
-
如果 transport.
[[State]]为"connecting",则将 transport.[[State]]设置为"failed"。这也需要在 worker 中完成。参见 #127 和 whatwg/html#6731。
6.8. 垃圾回收
当 WebTransport
对象的 [[State]]
为 "connecting" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任何
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
被 锁定,或 ready、
draining、
closed
promise 被观察时,不能被垃圾回收。
当 WebTransport
对象的 [[State]]
为 "connected" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任何
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
被 锁定,或 draining
或 closed
promise 被观察时,不能被垃圾回收。
当 WebTransport
对象的 [[State]]
为 "draining" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任何
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
被 锁定,或 closed
promise 被观察时,不能被垃圾回收。
当一个 WebTransport
对象的 WebTransport
会话已建立,且有排队待发送到网络的数据(包括在
[[Datagrams]].[[OutgoingDatagramsQueue]]
的数据报),不能被垃圾回收。
如果 WebTransport
对象在 底层连接
仍然打开时被垃圾回收,用户代理必须
以应用错误码
0 和应用错误消息 "" 终止 WebTransport 会话。
6.9. 配置
dictionary {WebTransportHash DOMString ;algorithm BufferSource ; };value dictionary WebTransportOptions {boolean allowPooling =false ;boolean requireUnreliable =false ;sequence <WebTransportHash >serverCertificateHashes ;WebTransportCongestionControl congestionControl = "default"; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams =null ; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams =null ;sequence <DOMString >protocols = [];DatagramsReadableMode datagramsReadableMode ; };enum {WebTransportCongestionControl ,"default" ,"throughput" , };"low-latency" enum {DatagramsReadableMode };"bytes"
WebTransportOptions 是用于决定如何建立和使用 WebTransport 会话的参数字典。
allowPooling, 类型为 boolean,默认值为false-
当设置为 true 时,WebTransport 会话可以被池化,即其 底层连接 可以与其他 WebTransport 会话共享。
requireUnreliable, 类型为 boolean,默认值为false-
当设置为 true 时,如果无法建立 HTTP/3 连接,则不能通过 HTTP/2 连接建立 WebTransport 会话。
serverCertificateHashes, 类型为 sequence<WebTransportHash>-
该选项仅支持专用连接的传输协议。对于不支持此功能的传输协议,如果该字段非空,则会抛出
NotSupportedError异常。如果支持且非空,用户代理只有在能够成功验证证书哈希,并满足 自定义证书要求时,才认为服务器证书可信。用户代理必须忽略任何使用未知
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>,默认值为[]-
可选应用层协议名称数组。服务器可以选择性地选择首选应用协议并通知客户端。如果没有提供合适的协议,服务器可能会拒绝请求。
datagramsReadableMode, 类型为 DatagramsReadableMode-
可选地指定应用偏好是否为入向数据报使用可读字节流。否则,将使用默认的可读流。
注意: 默认可读流用于检测零长度数据报。 但可读字节流可以更高效地处理字节,尤其是在与BYOB reader配合使用时能减少拷贝。
-
设 cert 为 certificate,表示为 [RFC5280]中定义的 Certificate 消息的 DER 编码。
-
计算 cert 的 SHA-256 哈希并返回计算出的值。
-
设 referenceHash 为使用 certificate 计算证书哈希的结果。
-
对于 hashes 中的每个哈希 hash:
-
如果 hash.
value不为 null 且 hash.algorithm与 "sha-256" ASCII 大小写不敏感匹配:-
设 hashValue 为 hash.
value表示的字节序列。 -
如果 hashValue 等于 referenceHash,则返回 true。
-
-
-
返回 false。
自定义证书要求custom certificate requirements如下:该证书必须是 [RFC5280]中定义的 X.509v3 证书, Subject Public Key 字段中使用的密钥必须是允许的公钥算法之一, 当前时间必须在证书的有效期内,如[RFC5280]的第 4.1.2.5 节中所定义, 且有效期的总长度不得超过两周。用户代理可以对证书施加额外的实现定义的要求。
Subject Public Key Info 字段(以及因此,在 TLS CertificateVerify 消息中)中使用的允许的公钥算法的确切列表是实现定义的;但是,它必须包括使用 secp256r1 (NIST P-256) 命名组的 ECDSA([RFC3279], 第 2.3.5 节;[RFC8422]) 以提供可互操作的默认值。它不得包含 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是一个基本参数字典,它会影响
createUnidirectionalStream、
createBidirectionalStream
以及
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创建的
createUnidirectionalStream
和
createBidirectionalStream的行为。
dictionary WebTransportSendStreamOptions :WebTransportSendOptions {boolean waitUntilAvailable =false ; };
该字典应具有以下属性:
waitUntilAvailable, 类型为 boolean, 默认为false-
如果为 true,则
createUnidirectionalStream或createBidirectionalStream调用返回的 promise 将不会解决, 直到底层连接具有足够的流量控制信用额度来创建流,或者连接达到无法再创建传出流的状态。如果为 false,则如果在调用时没有可用的流量控制窗口,则将拒绝该 promise。
6.13.
WebTransportConnectionStats 字典
WebTransportConnectionStats字典包含有关WebTransport 会话的底层连接的 WebTransport 特定统计信息的
信息。
注意: 当使用池化时,池化在同一连接上的多个WebTransport 会话都接收相同的信息,即,该信息跨持有相同网络分区密钥的池化的会话公开。
注意: 任何不可用的统计信息都将从WebTransportConnectionStats字典中缺失。
dictionary WebTransportConnectionStats {unsigned long long bytesSent = 0;unsigned long long packetsSent = 0;unsigned long long bytesLost = 0;unsigned long long packetsLost = 0;unsigned long long bytesReceived = 0;unsigned long long packetsReceived = 0;required DOMHighResTimeStamp smoothedRtt ;required DOMHighResTimeStamp rttVariation ;required DOMHighResTimeStamp minRtt ;required WebTransportDatagramStats ;datagrams unsigned long long ?estimatedSendRate =null ;boolean atSendCapacity =false ; };
该字典应具有以下属性:
bytesSent, 类型为 unsigned long long, 默认为0-
在底层连接上发送的字节数,包括重传。 不包括 UDP 或任何其他外部帧。
packetsSent, 类型为 unsigned long long, 默认为0-
在底层连接上发送的数据包数,包括那些被确定为丢失的数据包。
bytesLost, 类型为 unsigned long long, 默认为0-
在底层连接上丢失的字节数(不会单调递增,因为随后可能会收到声明为丢失的数据包)。 不包括 UDP 或任何其他外部帧。
packetsLost, 类型为 unsigned long long, 默认为0-
在底层连接上丢失的数据包数(不会单调递增,因为随后可能会收到声明为丢失的数据包)。
bytesReceived, 类型为 unsigned long long, 默认为0-
在底层连接上收到的总字节数,包括流的重复数据。不包括 UDP 或任何其他外部帧。
packetsReceived, 类型为 unsigned long long, 默认为0-
在底层连接上收到的总数据包数,包括无法处理的数据包。
smoothedRtt, 类型为 DOMHighResTimeStamprttVariation, 类型为 DOMHighResTimeStampminRtt, 类型为 DOMHighResTimeStampestimatedSendRate, 类型为 unsigned long long, nullable, 默认为null-
用户代理将发送排队数据的估计速率,以每秒比特数为单位。 此速率适用于共享WebTransport 会话的所有流和数据报, 并且由拥塞控制算法计算(可能由
congestionControl选择)。 此估计不包括任何帧开销,并且表示可以发送应用程序有效负载的速率。如果用户代理当前没有估计值,则成员必须为null值。即使在先前的结果中不是null,该成员也可以是null。 atSendCapacity, 类型为 boolean, 默认为false-
值 false 表示
estimatedSendRate可能受应用程序限制, 这意味着应用程序发送的数据明显少于拥塞控制器允许的数据。当应用程序受到限制时,拥塞控制器可能会对可用的网络容量产生较差的估计。值 true 表示应用程序正在以网络容量发送数据,并且
estimatedSendRate反映了应用程序可用的网络容量。当atSendCapacity为true时,estimatedSendRate反映了一个上限。 只要应用程序发送速率持续,estimatedSendRate将适应网络状况。但是,允许estimatedSendRate为null,而atSendCapacity为 true。
6.14.
WebTransportDatagramStats 字典
WebTransportDatagramStats字典包含有关通过底层连接进行数据报传输的统计信息。
dictionary WebTransportDatagramStats {unsigned long long droppedIncoming = 0;unsigned long long expiredIncoming = 0;unsigned long long expiredOutgoing = 0;unsigned long long lostOutgoing = 0; };
该字典应具有以下属性:
droppedIncoming, 类型为 unsigned long long, 默认为0expiredIncoming, 类型为 unsigned long long, 默认为0-
由于传入数据报早于
incomingMaxAge,因此在从datagrams的readable读取之前被丢弃的传入数据报的数量。 expiredOutgoing, 类型为 unsigned long long, 默认为0-
由于排队发送的数据报早于
outgoingMaxAge,因此在能够发送之前被丢弃的排队发送的数据报的数量。 lostOutgoing, 类型为 unsigned long long, 默认为0
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 步骤如下:
-
返回 this 的
[[SendGroup]]。
setter 步骤,给定 value:
-
如果 value 非 null,且 value.
[[Transport]]不等于 this.[[Transport]], 抛出InvalidStateError异常。 -
设置 this.
[[SendGroup]]为 value。
-
sendOrder,类型为 long long-
getter 步骤如下:
-
返回 this 的
[[SendOrder]]。
setter 步骤,给定 value:
-
设置 this.
[[SendOrder]]为 value。
-
7.2. 方法
getStats()-
收集特定于此
WebTransportSendStream的性能的统计信息,并异步报告结果。调用 getStats 时,用户代理必须运行以下步骤:
-
设p为一个新的 promise。
-
并行运行以下步骤:
-
收集特定于此
WebTransportSendStream的统计信息。 -
等待统计信息准备就绪。
-
使用transport将网络任务排队以运行以下步骤:
-
设stats为一个新的
WebTransportSendStreamStats对象,表示收集的统计信息。 -
使用stats解析p。
-
-
-
返回p。
-
getWriter()-
此方法必须以与从
WritableStream继承的getWriter相同的方式实现, 只是代替创建WritableStreamDefaultWriter,它必须创建一个WebTransportWriter,其中包含this。
7.3. 内部插槽
WebTransportSendStream
拥有以下内部槽。
| 内部槽 | 描述(非规范性) |
|---|---|
[[InternalStream]]
| 一个出向单向或双向 WebTransport 流。 |
[[PendingOperation]]
| 表示待写或关闭操作的 promise,或为 null。 |
[[Transport]]
| 拥有此 WebTransport
的 WebTransportSendStream。
|
[[SendGroup]]
| 可选的 WebTransportSendGroup,
或为 null。
|
[[SendOrder]]
| 可选的发送顺序号,默认值为 0。 |
[[AtomicWriteRequests]]
| 一个有序集合 ,包含 promise,跟踪底层 sink 队列中属于原子的写请求子集。 |
[[BytesWritten]]
| 已写入流的字节数。 |
[[CommittedOffset]]
| 流中的偏移量,记录即使流已中止发送,也会传递给对端的字节数; 参见 [RELIABLE-RESET]。 |
7.4. 过程
要创建
一个WebTransportSendStream,
使用一个出向单向或双向
WebTransport 流
internalStream、一个WebTransport
transport、sendGroup和sendOrder,请执行以下步骤:
-
设stream为一个新的
WebTransportSendStream,具有:[[InternalStream]]-
internalStream
[[PendingOperation]]-
null
[[Transport]]-
transport
[[SendGroup]]-
sendGroup
[[SendOrder]]-
sendOrder
[[AtomicWriteRequests]]-
一个空的 ordered set,其元素是 promise。
[[BytesWritten]]-
0
[[CommittedOffset]]-
0
-
设writeAlgorithm为一个动作,该动作将chunk写入到stream,给定chunk。
-
设closeAlgorithm为一个动作,该动作关闭stream。
-
设abortAlgorithm为一个动作,该动作使用reason中止stream,给定reason。
-
设置stream,其中writeAlgorithm设置为writeAlgorithm,closeAlgorithm设置为closeAlgorithm, abortAlgorithm设置为abortAlgorithm。
-
设abortSignal为stream的[[controller]].[[abortController]].[[signal]]。
-
将以下步骤添加到abortSignal。
-
设pendingOperation为stream的
[[PendingOperation]]。 -
如果pendingOperation为 null,则中止这些步骤。
-
将stream的
[[PendingOperation]]设置为 null。 -
设reason为abortSignal的中止原因。
-
设promise为中止流与reason的结果。
-
-
将stream附加到transport的
[[SendStreams]]。 -
返回stream。
WebTransportSendStream
stream,运行以下步骤:
-
设transport为stream的
[[Transport]]。 -
如果chunk不是一个
BufferSource, 则返回一个被拒绝的 promise,并带有一个TypeError。 -
设promise为一个新的 promise。
-
设bytes为字节序列(chunk表示)的副本。
-
将stream的
[[PendingOperation]]设置为promise。 -
设inFlightWriteRequest为 stream的inFlightWriteRequest。
-
如果stream的
[[AtomicWriteRequests]]包含inFlightWriteRequest,则设atomic为 true,否则为 false。 -
并行运行以下步骤:
-
如果atomic为 true,并且当前的流量控制窗口太小,无法完全发送bytes,则中止剩余步骤,并使用transport将网络任务排队,以运行以下子步骤:
-
将stream的
[[PendingOperation]]设置为 null。 -
中止stream上的所有原子写入请求。
-
-
否则,在stream的
[[InternalStream]]上发送bytes,并等待操作完成。 此发送可以与先前排队的流和数据报的发送交错,以及尚未排队以通过此传输发送的流和数据报。用户代理可以有一个缓冲区来提高传输性能。这样的缓冲区应该有一个固定的上限,以将反压信息传递给
WebTransportSendStream的用户。此发送必须饿死 直到所有在具有相同
[[SendGroup]]和更高[[SendOrder]]的流上排队等待发送的字节,既不是出错,也没有被流量控制阻止,都已发送。我们并行访问stream的
[[SendOrder]]。 用户代理应该响应发送期间这些值的实时更新,但细节是实现定义的。注意:重新传输的排序是实现定义的, 但强烈建议用户代理优先重新传输具有更高
[[SendOrder]]值的 数据。用户代理应该在所有未被饿死的流之间公平地分配带宽。
注意:这里的公平性定义是实现定义的。
-
如果由于网络错误导致上一步失败,则中止剩余步骤。
注意:我们不在此处拒绝promise,因为我们在其他地方处理网络错误,并且这些步骤拒绝stream的
[[PendingOperation]]。 -
否则,使用transport将网络任务排队,以运行以下步骤:
-
将stream的
[[PendingOperation]]设置为 null。 -
将bytes的长度添加到stream的
[[BytesWritten]]。 -
如果stream的
[[AtomicWriteRequests]]包含inFlightWriteRequest,则删除inFlightWriteRequest。 -
使用 undefined解析promise。
-
-
-
返回promise。
注意:从此算法(或write(chunk))返回的 promise 的实现不一定意味着该块已通过服务器[QUIC]确认。它可能只是意味着该块已附加到缓冲区。为了确保该块到达服务器,服务器需要发送一个应用程序级别的确认消息。
WebTransportSendStream
stream,请执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 promise 为一个新的 promise。
-
移除 stream 从 transport.
[[SendStreams]]。 -
将 stream.
[[PendingOperation]]设置为 promise。 -
并行运行以下步骤:in parallel:
-
发送 FIN 到 stream.
[[InternalStream]]并等待操作完成。 -
等待 stream.
[[InternalStream]]进入 “所有数据已提交” 状态。[QUIC] -
排队一个网络任务 使用 transport 来运行以下步骤:
-
将 stream.
[[PendingOperation]]设置为 null。 -
解析 promise 并返回 undefined。
-
-
-
返回 promise。
WebTransportSendStream
stream,参数为 reason,请执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 promise 为一个新的 promise。
-
令 code 为 0。
-
移除 stream 从 transport.
[[SendStreams]]。 -
如果 reason 是
WebTransportError且 reason.[[StreamErrorCode]]不为 null,则将 code 设为 reason.[[StreamErrorCode]]。 -
如果 code < 0,则将 code 设为 0。
-
如果 code > 4294967295,则将 code 设为 4294967295。
-
令 committedOffset 为 stream.
[[CommittedOffset]]。注意: code 的有效值为 0 至 4294967295(含)。如果 底层连接 使用 HTTP/3,则该 code 会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 区间的数值,详见 [WEB-TRANSPORT-HTTP3]。
-
并行运行以下步骤:
-
中止发送 stream.
[[InternalStream]],参数为 code 和 committedOffset。
-
-
返回 promise。
WebTransportSendStream
stream 上中止所有原子写请求,请执行以下步骤:
-
令 writeRequests 为 stream.writeRequests。
-
令 requestsToAbort 为 stream.
[[AtomicWriteRequests]]。 -
如果 writeRequests 包含某个不在 requestsToAbort 中的 promise,则 出错 stream,错误类型为
AbortError, 并中止这些步骤。 -
对于每个 promise 属于 requestsToAbort,拒绝该 promise,错误类型为
AbortError。
7.5. 接收来自服务器的中止信号
WebTransportSendStream
stream 收到来自服务器的
接收中止信号时,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 code 为附加在 接收中止信号上的应用协议错误码。
注意: code 的有效值为 0 到 4294967295(含)。如果 底层连接使用 HTTP/3,则该 code 会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 区间的数字,详见 [WEB-TRANSPORT-HTTP3]。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
移除 stream 从 transport.
[[SendStreams]]。 -
令 error 为新 创建的
WebTransportError, 其source为"stream",streamErrorCode为 code。 -
如果 stream.
[[PendingOperation]]不为 null,则拒绝 stream.[[PendingOperation]],错误为 error。 -
报错 stream,错误为 error。
-
7.6. WebTransportSendStreamStats 字典
WebTransportSendStreamStats 字典
包括一个 WebTransportSendStream
的特定统计信息。
dictionary WebTransportSendStreamStats {unsigned long long bytesWritten = 0;unsigned long long bytesSent = 0;unsigned long long bytesAcknowledged = 0; };
字典应具有以下属性:
bytesWritten, 类型为 unsigned long long, 默认值为0-
应用程序已成功写入此
WebTransportSendStream的总字节数。此数字只能增加。 bytesSent, 类型为 unsigned long long, 默认值为0-
指示应用程序写入此
WebTransportSendStream的字节已至少发送一次的进度。此数字只能增加,并且始终小于或等于bytesWritten。注意: 此值仅表示单个流上的应用数据发送进度,不包括任何网络开销。
bytesAcknowledged, 类型为 unsigned long long, 默认值为0-
指示应用程序写入此
WebTransportSendStream的字节已发送并通过服务器的 QUIC ACK 机制确认接收的进度。只有连续的字节(直到但不包括第一个未确认的字节)被计入。此数字只能增加,并且始终小于或等于bytesSent。注意: 如果连接是通过 HTTP/2,则此值将与
bytesSent匹配。
8. 接口
WebTransportSendGroup
WebTransportSendGroup
是一个可选的组织对象,用于跟踪分布在许多个单独
(通常是 严格排序的)
WebTransportSendStream
上的数据传输。
WebTransportSendStream
可以在创建时或通过赋值其 sendGroup 属性,被归为最多一个 分组到一个
WebTransportSendGroup。默认情况下,它们是
未分组的。
用户代理在为发送 WebTransportSendStream
分配带宽时,
会将 WebTransportSendGroup
视为同等。
每个 WebTransportSendGroup
还会为评估 sendOrder
编号建立一个独立的数字空间。
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransportSendGroup Promise <WebTransportSendStreamStats >getStats (); };
一个 WebTransportSendGroup
总是通过 创建过程生成。
8.1. 方法
getStats()-
聚合所有
WebTransportSendStream分组到 this sendGroup 下的流的统计信息,并异步返回结果。调用 getStats 时,用户代理必须运行以下步骤:
-
令 p 为一个新的 promise。
-
令 streams 为所有
WebTransportSendStream,其[[SendGroup]]等于 this。 -
并行运行以下步骤:
-
从 streams 中所有流收集统计信息。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
令 stats 为一个新的 new
WebTransportSendStreamStats对象,表示已收集统计信息的聚合数值。 -
解决 p,值为 stats。
-
-
-
返回 p。
-
8.2. 内部槽
WebTransportSendGroup
拥有以下内部槽。
| 内部槽 | 描述(非规范性) |
|---|---|
[[Transport]]
| 拥有此 WebTransport
对象的 WebTransportSendGroup。
|
8.3. 过程
要 创建一个
WebTransportSendGroup
,并绑定一个 WebTransport
transport,请执行以下步骤:
-
让 sendGroup 为一个新的
WebTransportSendGroup,绑定:[[Transport]]-
transport
-
返回 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性能的特定统计数据,并异步报告结果。当调用 getStats 时,用户代理必须执行以下步骤:
-
创建一个新的 p promise。
-
并行运行以下步骤:
-
收集此
WebTransportReceiveStream的特定统计数据。 -
排队一个网络任务 使用 transport 执行以下步骤:
-
让 stats 为一个新的
WebTransportReceiveStreamStats对象,表示收集到的统计数据。 -
解析 p 并返回 stats。
-
-
-
返回 p。
-
9.2. 内部槽
WebTransportReceiveStream
拥有以下内部槽。
| 内部槽 | 描述(非规范性) |
|---|---|
[[InternalStream]]
| 一个入向单向或双向 WebTransport 流。 |
[[Transport]]
| 拥有此 WebTransport
对象的 WebTransportReceiveStream。
|
9.3. 过程
要创建
一个WebTransportReceiveStream,
使用一个入向单向或双向
WebTransport 流
internalStream 和一个 WebTransport
transport,请执行以下步骤:
-
让 stream 为一个新的
WebTransportReceiveStream,绑定:[[InternalStream]]-
internalStream
[[Transport]]-
transport
-
让 pullAlgorithm 为从 stream 拉取字节 的动作。
-
让 cancelAlgorithm 为取消 stream 的动作,并提供 reason。
-
使用字节读取支持设置 stream,将 pullAlgorithm 设置为 pullAlgorithm, 将 cancelAlgorithm 设置为 cancelAlgorithm。
-
将 stream 添加到 transport.
[[ReceiveStreams]]。 -
返回 stream.
要 拉取字节从一个 WebTransportReceiveStream
stream,请执行以下步骤。
-
将 transport 设为 stream.
[[Transport]]. -
将 internalStream 设为 stream.
[[InternalStream]]. -
创建一个新的 promise.
-
将 buffer, offset, 和 maxBytes 初始化为 null.
-
如果 stream 的 当前 BYOB 请求视图 不为空:
-
设置 offset 为 stream 的 当前 BYOB 请求视图.[[ByteOffset]].
-
设置 maxBytes 为 stream 的 当前 BYOB 请求视图 的 字节长度.
-
设置 buffer 为 stream 的 当前 BYOB 请求视图 的 底层缓冲区.
-
-
否则:
-
将 offset 设置为 0.
-
设置 maxBytes 为一个 实现定义 的大小.
-
将 buffer 设置为一个新的
ArrayBuffer,大小为 maxBytes. 如果分配失败,返回 一个被拒绝的 promise,错误为RangeError.
-
-
并行运行以下步骤:
-
写入从 internalStream 读取的字节到 buffer,偏移量为 offset,最多 maxBytes 字节. 等待至少读取一个字节或接收 FIN. 设定 read 为读取字节数,设定 hasReceivedFIN 为是否接收到 FIN.
-
如果上述步骤失败,中止剩余步骤.
-
排队一个网络任务 使用 transport 执行以下步骤:
-
如果 read > 0:
-
设置 view 为一个新的
Uint8Array,使用 buffer, offset, 和 read. -
放入队列 view 到 stream.
-
-
如果 hasReceivedFIN 为 true:
-
移除 stream 从 transport.
[[ReceiveStreams]]. -
关闭 stream.
-
-
解析 promise 并返回 undefined.
-
-
-
返回 promise.
要取消一个 WebTransportReceiveStream
stream,参数为 reason,请执行以下步骤。
-
令 transport 为 stream.
[[Transport]]。 -
令 internalStream 为 stream.
[[InternalStream]]。 -
令 promise 为一个新的 promise。
-
令 code 为 0。
-
如果 reason 是
WebTransportError且 reason.[[StreamErrorCode]]不为 null,则将 code 设为 reason.[[StreamErrorCode]]。 -
如果 code < 0,则将 code 设为 0。
-
如果 code > 4294967295,则将 code 设为 4294967295。
注意: code 的有效值为 0 到 4294967295(含)。如果 底层连接使用 HTTP/3,则该 code 会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 区间的数值,详见 [WEB-TRANSPORT-HTTP3]。
-
移除 stream 从 transport.
[[SendStreams]]。 -
并行运行以下步骤:
-
返回 promise。
9.4. 接收来自服务器的发送中止信号
WebTransportReceiveStream
stream 收到来自服务器的
发送中止信号时,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 code 为附加在 发送中止信号上的应用协议错误码。
注意: code 的有效值为 0 到 4294967295(含)。如果 底层连接使用 HTTP/3,则该 code 会被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 区间的数字,详见 [WEB-TRANSPORT-HTTP3]。
-
队列一个网络任务,参数为 transport,执行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则终止这些步骤。 -
移除 stream 从 transport.
[[ReceiveStreams]]。 -
令 error 为新 创建 的
WebTransportError, 其source为"stream",streamErrorCode为 code。 -
报错 stream,错误为 error。
-
9.5. WebTransportReceiveStreamStats 字典
WebTransportReceiveStreamStats 字典
包括一个 WebTransportReceiveStream
的特定统计信息。
dictionary WebTransportReceiveStreamStats {unsigned long long bytesReceived = 0;unsigned long long bytesRead = 0; };
字典应具有以下属性:
bytesReceived, 类型为 unsigned long long, 默认值为0-
指示服务器应用程序的字节进度,这些字节是针对此
WebTransportReceiveStream到目前为止已接收的数量。只有连续的字节(直到但不包括第一个丢失的字节)被计入。此数字只能增加。注意: 此值仅表示单个流上的应用数据接收进度,不包括任何网络开销。
bytesRead, 类型为 unsigned long long, 默认值为0-
应用程序已成功读取此
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, 只读-
获取器步骤是返回 this 的
[[Readable]]。 writable, 类型为 WebTransportSendStream, 只读-
获取器步骤是返回 this 的
[[Writable]]。
10.3. 过程
WebTransportBidirectionalStream
,使用
双向
WebTransport 流 internalStream、一个 WebTransport
对象 transport 和 sendOrder,请执行以下步骤。
-
将 readable 设为通过 创建一个
WebTransportReceiveStream,并绑定 internalStream 和 transport 的结果。 -
将 writable 设为通过 创建一个
WebTransportSendStream,并绑定 internalStream、transport 和 sendOrder 的结果。 -
将 stream 设为一个新的
WebTransportBidirectionalStream,绑定以下内容:[[Readable]]-
readable
[[Writable]]-
writable
[[Transport]]-
transport
-
返回 stream.
11.
WebTransportWriter 接口
WebTransportWriter
是 WritableStreamDefaultWriter
的子类,添加了两个方法。
一个 WebTransportWriter
总是通过 创建
过程生成。
[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因缺乏可用流量控制信用而失败。注意: 原子写操作在排队到非原子写操作之后仍可能阻塞。如果原子写操作被拒绝,则此刻排队在其后的所有内容都将被拒绝。任何以这种方式被拒绝的非原子写操作将错误流。因此,建议应用程序始终等待原子写操作完成。
当调用
atomicWrite时,用户代理必须执行以下步骤:-
让 p 为在
write(chunk)上调用WritableStreamDefaultWriter的结果,并传递 chunk。 -
附加 p 到 stream.
[[AtomicWriteRequests]]。 -
返回对 p 的结果进行反应 (响应),并执行以下步骤:
-
如果 stream.
[[AtomicWriteRequests]]包含 p, 移除 p。 -
如果 p 因原因 r 被拒绝,则返回 一个被拒绝的 promise,理由为 r。
-
返回 undefined。
-
-
commit()-
commit方法会将流的[[CommittedOffset]]更新为已写入该流的字节数 ([[BytesWritten]])。 这样可以确保这些字节能够可靠地传递给对端,即使写入被中止,导致流中止发送。 该机制参见 [RELIABLE-RESET]。注意: 这无法保证连接失败时的数据可达,仅能保证当流中止发送时的可靠传递。
当为 stream 调用
commit时,用户代理必须执行以下步骤:-
将 transport 设为 stream.
[[Transport]]。 -
将 stream.
[[CommittedOffset]]设置为 stream.[[BytesWritten]]的值。
-
11.2. 过程
要 创建一个
WebTransportWriter
,并绑定一个 WebTransportSendStream
stream,请执行以下步骤:
-
将 writer 设为一个新的
WebTransportWriter。 -
运行 new WritableStreamDefaultWriter(stream) 构造步骤,传递 writer 作为 this,传递 stream 作为构造函数参数。
-
返回 writer。
12.
WebTransportError 接口
WebTransportError 是 DOMException
的子类,表示:
-
来自服务器或网络的错误,或
-
客户端发起的中止操作的原因。
[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 = "stream"; [source Clamp ]unsigned long ?=streamErrorCode null ; };enum {WebTransportErrorSource ,"stream" , };"session"
12.1. 内部插槽
一个 WebTransportError
具有以下内部槽。
| 内部槽 | 描述 (非规范性) |
|---|---|
[[Source]]
| 一个 WebTransportErrorSource
,指示此错误的来源。
|
[[StreamErrorCode]]
| 此错误的应用协议错误代码,或 null。 |
12.2. 构造函数
new WebTransportError(message, options)
构造函数的步骤如下:
-
将 this 的 name 设置为
"WebTransportError"。 -
将 this 的 message 设置为 message。
-
将 this 的内部槽设置如下:
[[Source]]-
options.
source [[StreamErrorCode]]-
options.
streamErrorCode
12.3. 属性
source,类型为 WebTransportErrorSource,只读-
getter 步骤为返回 this 的
[[Source]]。 streamErrorCode,类型为 unsigned long,只读,可为 null-
getter 步骤为返回 this 的
[[StreamErrorCode]]。
12.4. 序列化
WebTransportError
对象是 可序列化对象。
它们的 序列化步骤,给定 value 和 serialized,如下:
-
运行
DOMException的 序列化步骤,给定 value 和 serialized。 -
将 serialized.
[[Source]]设置为 value.[[Source]]。 -
将 serialized.
[[StreamErrorCode]]设置为 value.[[StreamErrorCode]]。
它们的 反序列化步骤,给定 serialized 和 value,如下:
-
运行
DOMException的 反序列化步骤,给定 serialized 和 value。 -
将 value.
[[Source]]设置为 serialized.[[Source]]。 -
将 value.
[[StreamErrorCode]]设置为 serialized.[[StreamErrorCode]]。
13. 协议映射
此部分为非规范性内容。
本节描述了本规范中定义的方法的底层协议行为,使用 [WEB-TRANSPORT-OVERVIEW]。 由于缓冲,因果关系可能不会立即显现。
| WebTransport 协议行为 | API 效果 |
|---|---|
| 会话 耗尽 | 等待 wt.draining
|
如果 底层连接 使用 HTTP/3,则适用于从 [WEB-TRANSPORT-HTTP3] 的以下协议行为。
在 WebTransportError
错误中的应用 streamErrorCode
转换为 httpErrorCode,反之亦然,如 [WEB-TRANSPORT-HTTP3]
第4.3节 中所述。
| API 方法 | QUIC 协议行为 |
|---|---|
writable.abort(error)
| 中止发送到 STREAM,带 httpErrorCode 和与该 [[CommittedOffset]]
对应的 offset,以及任何流头部;参见 [RELIABLE-RESET]
|
writable.close()
| 发送 STREAM 并设置 FIN 位 |
writable.getWriter().write(chunk)()
| 发送 STREAM |
writable.getWriter().close()
| 发送 STREAM 并设置 FIN 位 |
writable.getWriter().abort(error)
| 中止发送到 STREAM,带 httpErrorCode 和与该 [[CommittedOffset]]
对应的 offset,以及任何流头部;参见 [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 位 | (await
readable.getReader().read()).done
|
| 接收 RESET_STREAM,带 httpErrorCode | 报错 readable
,错误为 streamErrorCode
|
| 会话正常终止,带 closeInfo | (await wt.closed).closeInfo,
并且
报错所有未关闭的流
|
| 网络错误 | (await wt.closed)
拒绝,并且
报错所有未关闭的流
|
注意: 如 [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 效果 |
|---|---|
| 会话draining | await wt.draining
|
如果底层连接使用 HTTP/2,则适用 [WEB-TRANSPORT-HTTP2] 中的协议行为。注意,与 HTTP/3 不同,流错误码不需要转换为 HTTP 错误码,反之亦然。
| API 方法 | HTTP/2 协议行为 |
|---|---|
writable.abort(error)
| 中止发送到 WT_STREAM,带 error |
writable.close()
| 发送 WT_STREAM 并设置 FIN 位 |
writable.getWriter().write()
| 发送 WT_STREAM |
writable.getWriter().close()
| 发送 WT_STREAM 并设置 FIN 位 |
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
|
| 接收 WT_STREAM 并设置 FIN 位 | (await
readable.getReader().read()).done
|
| 接收 WT_RESET_STREAM,带 error | 报错 readable
,错误为 streamErrorCode
|
| 会话正常终止,带 closeInfo | (await wt.closed).closeInfo,
并且
报错所有未关闭的流
|
| 网络错误 | (await wt.closed)
拒绝,并且
报错所有未关闭的流
|
| 会话draining | await wt.draining
|
14. 隐私与安全注意事项
此部分为非规范性内容;它未指定任何新的行为,而是总结了规范其他部分中已经存在的信息。
14.1. 通信机密性
通信正在进行的事实无法对能够观察网络的对手隐瞒,因此这必须被视为公开信息。
本文件中描述的所有传输协议都使用 TLS [RFC8446] 或语义上等效的协议,从而提供了 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] 中所述,包括:
-
确保远程服务器知道正在使用 WebTransport 协议,并确认远程服务器愿意使用 WebTransport 协议。[WEB-TRANSPORT-HTTP3] 使用 ALPN [RFC7301]、 HTTP/3 设置和
:protocol伪标头的组合来标识 WebTransport 协议。[WEB-TRANSPORT-HTTP2] 使用 ALPN、 HTTP/2 设置和:protocol伪标头的组合来标识 WebTransport 协议。 -
允许服务器根据资源的来源过滤连接,该资源发起了传输会话。会话建立请求上的
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 和 [webrtc])提供了非常类似的网络功能。因此,添加 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 bytesof 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 datagramof wt. datagrams. readable) { // 处理数据报 } }
15.4. 使用 BYOB 读取器接收数据报
此部分为非规范性内容。
由于 datagrams
是可读字节流,你可以为其获取一个
BYOB
reader,
这样可以更精确地控制缓冲区分配,以避免数据拷贝。下面的示例将数据报读入一个 64kB 的内存缓冲区。
const wt= new WebTransport( url); for await ( const datagramof 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 bytesof 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 readableof wt. incomingUnidirectionalStreams) { // 使用 IFFE 单独消费流,报告每个流的错误 (( async () => { try { for await ( const bytesof readable) { processTheData( bytes); } } catch ( e) { console. error( e); } })()); } }
解码也可以通过管道传输到新的 WritableStreams,例如使用
TextDecoderStream。
此示例假定文本输出不应交错,因此一次只读取一个流。
async function receiveText( url, createWritableStreamForTextData) { const wt= new WebTransport( url); for await ( const readableof 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 dataof 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 readableof 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 dataof 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
接口,并已为在本规范中使用而进行了调整。