当前位置:首页 > 文章列表 > 文章 > 前端 > WebTransport 怎样选择双向流和 Datagram

WebTransport 怎样选择双向流和 Datagram

来源:17golang原创 2026-10-14 15:31:53 0浏览 收藏

我第一次把实时面板从单一 WebSocket 连接拆成 WebTransport 时,最容易混淆的不是连接 API,而是“所有消息都走同一条通道”。告警确认、配置变更和实时坐标对可靠性的要求并不一样。

判断方法可以先记成一句话:必须到达、必须保持顺序的数据,用双向流;允许丢失、下一次状态可以覆盖上一次的数据,用 Datagram。双向流也不是现成的消息队列,它只负责可靠的有序字节,应用层仍要处理消息边界。

官方文档:https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API

选择 WebTransport 通道时,先看业务数据能不能丢,再看它是否需要顺序;不要先被“低延迟”三个字带着走。

我先按数据性质拆开这两个通道

同一个 WebTransport 会话可以创建可靠的双向流,也可以通过 transport.datagrams 发送不可靠数据。双向流提供可读和可写两端,适合聊天文本、订单状态、配置变更这类必须完整接收的消息;Datagram 更适合“只要最新值”的数据,例如游戏位置、鼠标轨迹或实时仪表盘采样。

判断维度双向流Datagram
到达保证可靠传输允许丢失
顺序保证按字节顺序交付不保证顺序
适合数据命令、文本、结果、配置瞬时状态、采样、可覆盖更新
应用层工作需要 framing 区分消息需要接受丢包和乱序
WebTransport session 中双向流和 Datagram 的可靠性与业务数据边界静态说明图
图1:WebTransport 两类传输通道的静态结构说明图,展示可靠双向流与 Datagram 的职责边界,不是运行截图。

我在项目里会先给消息写一个“能不能重放”的判断:用户点击保存后返回的结果不能丢,所以走双向流;播放器已经产生了新位置,旧位置再送达也没有意义,所以可以走 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() 当作一条完整消息。

WebTransport 双向流通过长度前缀和接收缓冲区还原完整业务消息的静态说明图
图2:双向流消息 framing 的静态关系说明图,展示字节序列、长度前缀、缓冲区与消息解析器的关系,不是运行截图。

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。丢一条坐标通常只会让画面短暂不精确,丢一条确认结果却可能让两端状态永久分叉。

上手前我会检查这三个条件

  1. 安全上下文:浏览器接口要求 HTTPS 等安全上下文,开发环境要准备可信的本地 HTTPS 方案。
  2. 服务端能力:WebTransport 依赖 HTTP/3 服务端和对应的会话处理,不能只把 WebSocket URL 原样替换成新构造器。
  3. 浏览器支持:当前 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 的两种通道就不会因为名称相近而被混用。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Web Streams 怎样处理背压和取消Web Streams 怎样处理背压和取消
上一篇
Web Streams 怎样处理背压和取消
WebSocket 心跳怎样避免页面休眠后误判断线
下一篇
WebSocket 心跳怎样避免页面休眠后误判断线
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    471次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    530次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    550次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    501次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    318次使用