WebTransport 怎样选择双向流和 Datagram
来源:17golang原创
时间:2026-10-14 15:31:53 440浏览 收藏
我第一次把实时面板从单一 WebSocket 连接拆成 WebTransport 时,最容易混淆的不是连接 API,而是“所有消息都走同一条通道”。告警确认、配置变更和实时坐标对可靠性的要求并不一样。
判断方法可以先记成一句话:必须到达、必须保持顺序的数据,用双向流;允许丢失、下一次状态可以覆盖上一次的数据,用 Datagram。双向流也不是现成的消息队列,它只负责可靠的有序字节,应用层仍要处理消息边界。
官方文档:https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API
选择 WebTransport 通道时,先看业务数据能不能丢,再看它是否需要顺序;不要先被“低延迟”三个字带着走。
我先按数据性质拆开这两个通道
同一个 WebTransport 会话可以创建可靠的双向流,也可以通过 transport.datagrams 发送不可靠数据。双向流提供可读和可写两端,适合聊天文本、订单状态、配置变更这类必须完整接收的消息;Datagram 更适合“只要最新值”的数据,例如游戏位置、鼠标轨迹或实时仪表盘采样。
| 判断维度 | 双向流 | Datagram |
|---|---|---|
| 到达保证 | 可靠传输 | 允许丢失 |
| 顺序保证 | 按字节顺序交付 | 不保证顺序 |
| 适合数据 | 命令、文本、结果、配置 | 瞬时状态、采样、可覆盖更新 |
| 应用层工作 | 需要 framing 区分消息 | 需要接受丢包和乱序 |

我在项目里会先给消息写一个“能不能重放”的判断:用户点击保存后返回的结果不能丢,所以走双向流;播放器已经产生了新位置,旧位置再送达也没有意义,所以可以走 Datagram。这个判断比单纯比较 API 名称更稳定。
我在可靠消息里使用双向流时,额外补一层消息边界
流的可靠性只说明字节不会随意丢失或乱序,不代表发送端的一次 write() 就会对应接收端的一次 read()。多个写入可能合并,一次写入也可能被拆开,所以聊天消息、JSON 命令这类内容要在字节流之上定义 framing。
function encodeMessage(text) {
// 统一使用 UTF-8,并把消息长度放在前四个字节
const body = new TextEncoder().encode(text)
const frame = new Uint8Array(4 + body.length)
new DataView(frame.buffer).setUint32(0, body.length)
frame.set(body, 4)
return frame
}
async function sendMessage(transport, text) {
// 双向流保证字节可靠有序,但不替应用层定义消息边界
const stream = await transport.createBidirectionalStream()
const writer = stream.writable.getWriter()
try {
await writer.write(encodeMessage(text))
} finally {
// 释放 writer,避免长时间占用这个流的写入端
writer.releaseLock()
}
}
示例只展示发送侧的协议形状:长度前缀是四字节无符号整数,接收侧需要持续把 ReadableStream 的字节放入缓冲区,至少积累到完整长度后再交给 JSON 解析器或业务处理器。不要把一次 read() 当作一条完整消息。

Datagram 适合会被新状态覆盖的实时数据
Datagram 的优势是不用为过期状态排长队,但代价是应用必须接受数据可能没有到达,也可能顺序变化。我通常只把它用于“晚到就没有价值”的数据:例如每 50 毫秒发送一次光标位置,客户端收到新位置后就可以覆盖旧位置。
async function sendCursor(transport, x, y) {
// 坐标是瞬时状态,旧值晚到时不值得阻塞新值
const payload = JSON.stringify({ x, y, sentAt: Date.now() })
const writer = transport.datagrams.writable.getWriter()
try {
await writer.write(new TextEncoder().encode(payload))
} finally {
// 每次发送完成后释放 writer,避免把无关状态长期锁住
writer.releaseLock()
}
}
如果消息代表扣款、权限变更、聊天正文或服务端确认,就不要因为它“看起来很小”而使用 Datagram。丢一条坐标通常只会让画面短暂不精确,丢一条确认结果却可能让两端状态永久分叉。
上手前我会检查这三个条件
- 安全上下文:浏览器接口要求 HTTPS 等安全上下文,开发环境要准备可信的本地 HTTPS 方案。
- 服务端能力:WebTransport 依赖 HTTP/3 服务端和对应的会话处理,不能只把 WebSocket URL 原样替换成新构造器。
- 浏览器支持:当前 MDN 将 WebTransport 标为 Baseline 2026,但旧设备和部分浏览器仍可能不完整支持,生产页面应保留 WebSocket 或 HTTP 长轮询的降级路径。
async function chooseChannel(url, message) {
// 连接建立后再读取 reliability,避免把 pending 当成最终能力
const transport = new WebTransport(url)
await transport.ready
if (transport.reliability === 'reliable-only') {
// 只能使用可靠传输时,状态更新也要走流或退回旧方案
return { transport, channel: 'stream' }
}
// 只有允许不可靠传输时,才把可覆盖状态交给 Datagram
return { transport, channel: message.replaceable ? 'datagram' : 'stream' }
}
我的落地清单很短:先把消息分成“不可丢”和“可覆盖”两类;不可丢的数据定义 framing 并处理断线重建;可覆盖的数据记录序号或时间戳,收到旧包时直接丢弃;最后为不支持 WebTransport 的环境保留备用传输。
常见问题
双向流比 Datagram 更快吗?
不能只用“快慢”概括。Datagram 不为可靠性和顺序等待,适合低延迟状态;双向流提供可靠有序字节,适合不能丢的业务消息。选择应由数据价值决定。
双向流为什么还需要长度前缀?
因为流提供的是连续字节序列,不保留应用层消息边界。长度前缀、分隔符或固定长度协议都可以完成 framing,关键是发送和接收两端使用同一套规则。
Datagram 丢包后要不要自动重发?
如果每个数据包都是可替换状态,通常直接等待下一次采样更合理;如果必须重发才能保证业务完成,这条消息本质上已经需要可靠语义,应改用双向流或在应用层明确设计确认与重试。
总结一下:双向流负责可靠、有序的字节,Datagram 负责允许丢失的低延迟状态;双向流上面还要自己定义消息边界。把“能不能丢”和“是否需要顺序”写进协议设计,WebTransport 的两种通道就不会因为名称相近而被混用。
-
130 收藏
-
Golang · Go教程 | 1个月前 | HTTP · go · sse · 流式响应 · Go EventSource SSE Server-Sent Events http.Flusher ResponseController491 收藏
-
414 收藏
-
163 收藏
-
137 收藏
-
194 收藏
-
224 收藏
-
483 收藏
-
175 收藏
-
496 收藏
-
297 收藏
-
368 收藏
-
230 收藏
-
435 收藏
-
413 收藏
-
236 收藏
-
425 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习