简介
WebTransport 是什么?
WebTransport是浏览器提供的一套基于QUIC协议的 API 接口,方便浏览器和服务器之间进行实时数据传输,它填补了 Web 平台中的一些空白:
- 缺少类似 UDP 的网络 API
- 缺少类似于 WebSocket 但不受队头阻塞影响(Head of Line Blocking)的 API
WebTransport 特性
Webtransport 基于 QUIC 协议,其底层是 UDP。虽然是 UDP 是不可靠的传输协议,但是 QUIC 在 UDP 的基础上融合了 TCP、TLS、HTTP/2 等协议的特性,使得 QUIC 成为一种低时延、安全可靠的传输协议。可以简单理解 QUIC 把 TCP+TLS 的功能基于 UDP 重新实现了一遍。
WebTransport 提供了如下功能特性:
- 传输可靠数据流 (类似 TCP)
- 传输不可靠数据流(类似 UDP)
- 数据加密和拥塞控制(congestion control)
- 基于 Origin 的安全模型(校验请求方是否在白名单内,类似于 CORS 的Access-Control-Allow-Origin)
- 支持多路复用(类似于 HTTP2 的 Stream)
WebTransport 适用场景
- 不考虑数据传输可靠性和数据到达到顺序的场景,比如游戏中向 服务器 发送 游戏状态 数据
- 服务器消息推送
- 其它不考虑数据达到顺序的场景
API 使用
WebTransport 主要提供三种类型的 API
datagramReadable
和datagramWritable
,用于不可靠数据传输createBidirectionalStream
, 用于双向数据流可靠传输createUnidirectionalStream
, 用于单向数据流可靠传输
创建 WebTransport 对象
创建 WebTransport 对象,有一定的 URI 要求,格式为: quic-transport://domain:port/path
,如下所示:
1 | const transport = new WebTransport('quic-transport://localhost:4433/counter') |
transport.ready
返回一个 Promise,如果 QUIC 连接失败会报错。
transport.closed
也返回一个 Promise,QUIC 连接关闭时会执行
使用 WebTransport 时需要创建一个 QUIC Server, 可以基于 Python 库aioquic来创建服务器,也可以直接使用 Google Chrome 的样例代码。
不可靠数据数传
WebTransport 提供了类似于 UDP 的不可靠传输接口,分别为datagramReadable
和datagramWritable
。前者用于读取数据,后者用于发送数据。完整的样例如下所示:
1 | ;(async () => { |
在 上面代码中,核心代码为:transport.datagramWritable.getWriter()
以及transport.datagramReadable.getReader()
。
transport.datagramWritable.getWriter()
返回 一个 WritableStreamDefaultWriter对象,其write
方法用于 发送数据,注意数据必须为TypedArray数据类型, 代码中我们用TextEncoder.encode()将字符串转为了Uint8Array
transport.datagramReadable.getReader()
返回一个ReadableStreamDefaultReader对象,其read
方法用于读取数据,代码中我们用TextEncoder.decode()将Uint8Array
类似数据转为了字符串。
双向可靠数据流
如果需要保证可靠的数据传输并且需要返回实时结果,可以通过transport.createBidirectionalStream()
来创建可靠数据传输。这个接口的功能类似于 WebSocket,但优点在于不受对头阻塞影响。
1 | ;(async () => { |
注意发送可靠数据流时和 transport.datagramWritable
有所不同,每次发送数据,都需要创建一个transport.createBidirectionalStream()
对象,发送完毕后需要调用close()
将其关闭。
这个就是就是多路复用,可以非常高效、低成本的同时创建多个 Stream,而且多个 Stream 之间相互独立,不像 HTTP2 那样受对头阻塞的影响。
transport.createBidirectionalStream()
返回一个Promise<BidirectionalStream>
, BidirectionalStream
拥有readable
和writable
对象,分别用于可靠的发送数据和接受数据。
单向可靠数据流
如果想保证数据可靠到达,但是对返回结果不感兴趣,可以使用transport.createUnidirectionalStream()
时来创建单向数据流,它返回一个SendStream
对象,只可以发送数据。如果想获取返回的数据,可以调用transport.transport.incomingUnidirectionalStreams
来获取,但是数据顺序就不保证了。一个完整的样例如下所示:
1 | ;(async () => { |
小结
WebTransport 提供的三种 API 可以根据实际情况来使用:
- 不需要保证数据发送先后顺序,就选择
transport.datagramWritable
- 需要保证数据发送顺序,但是不关心返回值,可以选择
transport.createUnidirectionalStream()
- 需要保证数据发送顺序且关心返回结果,就选择
transport.createBidirectionalStream()
注意事项
WebTransport 现在只有 Google Chrome 支持,其标准也处于草案阶段,不建议使用生产环境。而且现阶段处于origin trial,也就是说,必须申请试用才可以使用。例如官方样例https://googlechrome.github.io/samples/webtransport/client.html就有类似的代码:
1 | <!-- QuicTransport origin trial token. See https://developers.chrome.com/origintrials/#/view_trial/-6744140441987317759 --> |
浏览器检测到origin-trial
才开启 WebTransport 功能。
如果向自己玩耍 WebTransport,可以通过mkcert生成下 HTTPS 证书,然后在 Google Chrome 时加上自定参数,例如 Mac 下启动 Google Chrome 需要加上如下类似代码:
1 | open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --origin-to-force-quic-on=localhost:4433 https://googlechrome.github.io/samples/webtransport/client.html |
具体代码可以参考https://github.com/GoogleChrome/samples/blob/gh-pages/quictransport/quic_transport_server.py.
以Mac为例子,在命令行依此执行如下代码,就可以启动一个 QUIC Server。
1 | brew install mkcert |