- 后端
- 微服务
【免费下载链接】grpc-web
gRPC for Web Clients
gRPC-Web 是 gRPC 的浏览器端 JavaScript 实现,浏览器客户端需要借助 Envoy 等代理才能访问 gRPC 服务。本文以仓库内 doc/streaming-roadmap.md 为核心,系统梳理 gRPC-Web 对流式 RPC 的完整规划:服务端流式(Server-streaming)当前已支持并将持续增强、客户端流式与半双工流式暂不支持的决策逻辑、计划基于 WebTransport 实现全双工双向流式的技术路线,以及团队为何明确放弃 WebSocket 方案的深层原因,并结合仓库源码给出可验证的实现证据。
一、路线图总览:四类流式能力的现状与规划
gRPC 共有四类 RPC 模式,它们在 gRPC-Web 中的支持状态截然不同:
| RPC 模式 | 数据流向 | gRPC-Web 当前状态 | 未来规划 |
|---|---|---|---|
| Unary(一元) | 单请求 → 单响应 | ✅ 已支持 | 持续维护 |
| Server-streaming(服务端流式) | 单请求 → 多响应 | ✅ 已支持(仅grpcwebtext模式) | 持续改进,见下文 |
| Client-streaming(客户端流式) | 多请求 → 单响应 | ❌ 不支持 | 随 WebTransport 全双工流式一并解决 |
| Full-duplex / half-duplex(双向流式) | 多请求 ↔ 多响应 | ❌ 不支持 | 依赖 WebTransport(2023+ 规划) |
这份路线图(doc/streaming-roadmap.md)明确列出了三个演进方向:服务端流式的增强、客户端流式与半双工流式的未来方案、基于 WebTransport 的全双工流式,并附带了对 WebSocket 的明确态度。主路线图文档 doc/roadmap.md 中"Streaming Support"与"Bidi Streaming"两节也分别指向本文档,可见流式能力是 gRPC-Web 整体演进的核心议题之一。
仓库中的 echo 示例(net/grpc/gateway/examples/echo/echo.proto)完整定义了这四类方法,其中客户端流式与双向流式的定义旁都注有同一行说明:"Notice: Client side streaming and Bidi streaming are not supported at the moment."(目前不支持客户端流式与双向流式)。这份 proto 与路线图互为印证:能力边界在服务定义和客户端运行时两个层面都是一致的。
二、服务端流式(Server-streaming):已支持,仍在演进
2.1 当前支持范围
服务端流式是 gRPC-Web 目前支持的两种 RPC 模式之一。仓库根目录 README.md 明确说明:
gRPC-web currently supports 2 RPC modes: Unary RPCs and Server-side Streaming RPCs(NOTE: Only when
grpcwebtextmode is used.)
即服务端流式调用必须在grpcwebtext(application/grpc-web-text)线格式模式下才能工作,使用二进制grpcweb(application/grpc-web+proto)模式时仅支持一元调用。这一点在 README.md 的 Wire Format Mode 小节有详细描述:
mode=grpcwebtext:payload 经 base64 编码,Content-type: application/grpc-web-text,一元与服务端流式调用均支持;mode=grpcweb:二进制 protobuf,Content-type: application/grpc-web+proto,仅支持一元调用。
客户端侧的服务端流式调用代码模式如下(摘自 README.md):
var stream = echoService.serverStreamingEcho(streamRequest, metadata); stream.on('data', function(response) { console.log(response.getMessage()); }); stream.on('status', function(status) { console.log(status.code); console.log(status.details); console.log(status.metadata); }); stream.on('end', function(end) { // stream end signal }); // to close the stream stream.cancel()2.2 服务端流式的底层实现链路
从源码看,服务端流式调用的入口在 javascript/net/grpc/web/grpcwebclientbase.js 的serverStreaming()方法:它先解析出 hostname,将"发起流式请求"包装为 invoker 后交给拦截器链,最终返回一个GrpcWebClientReadableStream。该流对象在 javascript/net/grpc/web/grpcwebclientreadablestream.js 中实现:
on()注册事件:支持data、status、metadata、end、error五类回调(源码 grpcwebclientreadablestream.js),与 README 示例中的用法一一对应;cancel()取消流:将aborted_置位并调用xhr.abort()(源码 grpcwebclientreadablestream.js),取消后的 ABORT 错误不会被当作异常抛出;- XHR 事件驱动:流数据在
READY_STATE_CHANGE事件中增量解析,流结束状态在COMPLETE事件中统一判定,并从响应头提取grpc-status/grpc-message与初始 metadata。
响应体的帧解析由 javascript/net/grpc/web/grpcwebstreamparser.js 完成,它实现goog.net.streams.StreamParser接口,状态机在INIT(帧字节)→LENGTH(4 字节长度)→MESSAGE(消息体)之间流转,支持流式分段输入(partial stream segments)。帧类型定义在源码 grpcwebstreamparser.js:
GrpcWebStreamParser.FrameType = { DATA: 0x00, // 数据帧 TRAILER: 0x80, // trailer 帧 };即服务端流式的响应在线上形如0x00 <message1> 0x00 <message2> ... 0x80 <trailers>,每条消息独立成帧,最终以 trailer 帧携带 gRPC 状态收尾。
2.3 路线图规划的服务端流式改进项
路线图文档为服务端流式列出的改进方向与时间预期如下:
- Fetch 取消支持(2024):当前客户端运行时基于 XHR(
goog.net.XhrIo)实现,流取消依赖xhr.abort();迁移到 Fetch 后需要补齐 Fetch 的AbortController取消语义; - 性能优化与 whatwg Fetch/streams 支持,包括 Service Workers(2024):Fetch/ReadableStream 相比 XHR 在流式吞吐、内存占用上有优势,也能让 gRPC-Web 请求进入 Service Worker 缓存/拦截体系;
- 完善 keep-alive 支持(通过 Envoy,2024+):长连接保活依赖代理层配合,见 doc/roadmap.md 中 Envoy 相关说明;
- 弥合 Fetch 与 XHR 之间的运行时行为差异(2024+):包括错误映射、超时语义、响应头可见性等细粒度行为对齐。
这些条目都属于持续打磨性质,说明服务端流式是当前"主战场":功能可用,但传输层基座(从 XHR 走向 Fetch/streams)的替换是未来两年的主线。
三、客户端流式与半双工流式:为何暂不支持
路线图对客户端流式的态度非常明确:
We don't plan to support client-streaming via Fetch/upload-streams. As a result, half-duplex bidi streaming won't be supported via Fetch/streams either.
也就是说,团队不计划通过 Fetch 的upload-streaming(请求体流式上传)能力去支持客户端流式;因此依赖"客户端先传完再收响应"的半双工双向流式,也不会借道 Fetch/streams 落地。这两类能力将被统一推迟到 WebTransport 全双工流式方案中一并解决。
这一决策的直接背景是附录中记录的 Chrome Origin Trial(详见第五节):upload-streaming规范尚未定稿,且 HTTP/1.1 下的安全性仍在讨论,无法作为可靠的技术底座。
从服务定义侧同样能看到印证:echo 示例中ClientStreamingEcho、FullDuplexEcho、HalfDuplexEcho三个方法均带"not supported at the moment"注释(echo.proto),生成客户端代码时不会为它们产生可用的流式调用实现。
四、全双工流式:押注 WebTransport
路线图规划的全双工(双向)流式方案是基于 WebTransport 实现,时间预期为 2023+(按文档编写时的表述)。WebTransport 的价值在于:它在浏览器与服务器之间提供真正的双向、多路复用字节流能力,天然契合 gRPC 全双工 RPC 的"客户端流 + 服务端流同时进行"的语义,而这正是 HTTP 请求/响应模型(含 Fetch/streams)无法覆盖的缺口。
主路线图 doc/roadmap.md 的 "Bidi Streaming" 一节同样声明"We plan to leverage WebTransport for bi-directional streaming",两份文档口径一致。
需要说明的是:从当前仓库代码结构看,javascript/net/grpc/web/ 目录下的运行时仍以 XHR 传输为主(GrpcWebClientBase内部直接构造XhrIo并xhr.send()),尚未包含 WebTransport 传输适配器;WebTransport 支持仍处于路线图规划阶段而非已落地功能。这也意味着客户端流式与双向流式在本文撰写时仍是"规划中"状态,读者不应期望在现网环境直接使用。
五、WebSocket:明确不采用,以及背后的 HTTP 兼容性逻辑
路线图给出了一个非常明确的负面决策:
We have no plan to support full-duplex streaming over WebSockets (over TCP or HTTP/2). We will not publish any experimental spec for gRPC over WebSockets either.
即:不打算在 WebSocket(无论跑在 TCP 还是 HTTP/2 之上)上支持全双工流式,也不会发布任何"gRPC over WebSocket"的实验性规范。理由集中在一点——WebSocket 与 HTTP(以及承载 Web 的普遍基础设施)不兼容:
- HTTP 回退总是必要:WebSocket 一旦不可用(网络设备、企业代理、部分移动网络等),必须回退到 HTTP 通道,这意味着每个使用 WebSocket 的方案都要维护两套传输逻辑;
- HTTP/2 上的 WebSocket 隧道普及度不足:虽然 IETF 有将 WebSocket 封装进 HTTP/2 的提案,但并未被广泛实现,无法形成可靠基线;
- 对比之下,WebTransport 构建在 HTTP/3 生态之上,与现有 Web 基础设施(TLS、代理、CDN)的兼容路径更清晰,这也是团队选择 WebTransport 而非 WebSocket 的关键考量。
六、附录解读:Chrome Origin Trial 与upload-streaming的来龙去脉
路线图附录记录了团队参与推进 whatwgfetch/upload-streamAPI 规范的背景:他们参与了 Chrome 的 Origin Trial(试验编号 3524066708417413121),目标是让浏览器能通过 Fetch API 流式上传请求体。
阻塞最终规范定稿的核心问题是:是否允许 upload-streaming 跑在 HTTP/1.1 上。团队立场是 HTTP/2 与 HTTP/1.1 都应启用 upload-streaming,并给出一个针对 gRPC-Web 场景的独特论据:
the server can't control the client deployment. As a result, if upload-streaming is only enabled over HTTP/2, a gRPC service will have to implement a non-streaming method as a fallback for each client-streaming method.
翻译过来就是:gRPC-Web 的服务端无法控制浏览器客户端的部署环境。如果 upload-streaming 只在 HTTP/2 下可用,那么任何提供客户端流式方法的 gRPC 服务,都必须为每个客户端流式方法额外实现一个非流式(一元)方法作为回退——这会显著增加服务端负担。因此他们主张 HTTP/1.1 同样支持上传流式。
正是由于该规范尚未定稿、且存在 HTTP 版本兼容性分歧,客户端流式方案无法建立在 Fetch/upload-streams 之上,最终被并入 WebTransport 路线——这正是第六节"暂不支持客户端流式"决策的完整逻辑链条。
七、结论与决策摘要
结合 doc/streaming-roadmap.md 与仓库实现,可以得出 gRPC-Web 流式能力的完整时间线认知:
- 服务端流式:当前可用(仅
grpcwebtext模式),底层由GrpcWebClientReadableStream+GrpcWebStreamParser提供事件驱动解析;2024 年起逐步将传输基座从 XHR 迁移到 Fetch/streams,补齐取消、Service Worker、keep-alive 等能力; - 客户端流式 / 半双工流式:不通过 Fetch/upload-streams 支持,等待 WebTransport 方案统一解决;
- 全双工流式:规划基于 WebTransport 实现(2023+ 规划),当前仓库代码尚无对应传输层实现;
- WebSocket:明确弃用,核心原因是与 HTTP 基础设施的不兼容及 HTTP/2 隧道普及度不足。
对于正在基于 gRPC-Web 做技术选型的读者,这份路线图的实用价值在于:短期可放心使用一元与服务端流式(注意选择grpcwebtext线格式并配置好 Envoy 代理,参考 net/grpc/gateway/examples/echo/envoy.yaml 中的grpc_web过滤器与 CORS 配置);若业务强依赖客户端流式或双向流式,则当前阶段需要评估服务端方案(如 gRPC over HTTP/2 直连、或等待 WebTransport 生态成熟),这与上游 doc/roadmap.md 的整体规划一致。
- 后端
- 微服务
【免费下载链接】grpc-web
gRPC for Web Clients
相关推荐
使用 Node.js 客户端库接入 Google Analytics Data API v1beta:安装、认证与报表实战指南
使用 Node.js 客户端库接入 Google Analytics Data API v1beta:安装、认证与报表实战指南 Google Analytics
后端微服务gRPC Python 数据传输四种调用模式:一元、客户端流、服务端流与双向流完整实战解析
gRPC Python 数据传输四种调用模式:一元、客户端流、服务端流与双向流完整实战解析 本指南基于 gRPC 官方仓库中的 data_transmissio
后端RPC框架微服务通信gRPC Python 四种数据传输模式实战:从 proto 定义到一元、客户端流、服务端流与双向流
gRPC Python 四种数据传输模式实战:从 proto 定义到一元、客户端流、服务端流与双向流 gRPC 在 Python 中支持四种 RPC 数据传输模
后端RPC框架微服务通信
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考