浏览器中 gRPC 的现状
gRPC 1.0 于 2016 年 8 月发布,此后已发展成为应用程序通信领域首屈一指的技术解决方案之一。它已被全球范围内的初创公司、企业以及开源项目所采用。其对多语言环境的支持、对性能的关注、类型安全以及开发者生产力,都改变了开发者设计架构的方式。
到目前为止,这些优势主要只对移动应用和后端开发者可用,而前端开发者则不得不继续依赖 JSON REST 接口作为其主要的信息交换方式。然而,随着 gRPC-Web 的发布,gRPC 有望成为前端开发者工具箱中一个宝贵的补充。
在这篇文章中,我将介绍 gRPC 在浏览器中的一些历史,探讨当前的发展现状,并分享对未来的展望。
起源
2016 年夏天,Google 和 Improbable1 的两个团队各自独立地开始着手实现一种可称为“浏览器版 gRPC”的技术。他们很快发现了彼此的工作,并共同定义了新协议的规范2。
gRPC-Web 规范
目前在浏览器中实现 HTTP/2 gRPC 规范3 是不可能的,因为浏览器 API 无法提供对请求进行足够细粒度控制的功能。例如:无法强制使用 HTTP/2,即使可以,也无法在浏览器中访问原始 HTTP/2 帧。gRPC-Web 规范从 HTTP/2 规范的角度出发,然后定义了其差异。这些差异主要包括:
- 支持 HTTP/1.1 和 HTTP/2。
- 在请求/响应体的最末尾发送 gRPC 尾部元数据(trailers),如 gRPC 消息头4中的新位所示。
- 一个强制性的代理,用于在 gRPC-Web 请求和 gRPC HTTP/2 响应之间进行转换。
技术细节
其基本思想是让浏览器发送普通的 HTTP 请求(使用 Fetch 或 XHR),并在 gRPC 服务器前端设置一个小代理,将请求和响应转换为浏览器可用的格式。


两种实现
Google 和 Improbable 的团队都在两个不同的仓库5,6中实现了该规范,且实现方式略有不同,导致两者都未完全符合规范,并且在很长一段时间内,它们都无法与对方的代理兼容7,8。
Improbable gRPC-Web 客户端9使用 TypeScript 实现,可通过 npm 获取,包名为 @improbable-eng/grpc-web
10。此外还提供一个 Go 代理,既可以作为一个包导入到现有的 Go gRPC 服务器中11,也可以作为一个独立的代理,用于将任意 gRPC 服务器暴露给 gRPC-Web 前端12。
Google gRPC-Web 客户端13使用 JavaScript 实现,基于 Google Closure library14。它可通过 npm 获取,包名为 grpc-web
15。它最初附带一个以 NGINX 扩展16形式实现的代理,但此后已转而使用 Envoy 代理 HTTP 过滤器17,该过滤器自 v1.4.0 版本起在所有版本中均可用。
功能集
所有 gRPC HTTP/2 实现都支持四种方法类型:一元(unary)、服务器端流式(server-side streaming)、客户端流式(client-side streaming)和双向流式(bi-directional streaming)。然而,gRPC-Web 规范并未明确要求支持任何客户端流式或双向流式,只规定在浏览器中实现 WHATWG Streams18后才会实现。
Google 客户端支持一元和服务器端流式,但仅限于使用 grpcwebtext
模式时。在 grpcweb
模式下,仅完全支持一元请求。这两种模式规定了在请求和响应中编码 protobuf 有效负载的不同方式。
Improbable 客户端支持一元和服务器端流式,其实现能够根据浏览器功能自动选择使用 XHR 或 Fetch。
下表总结了支持的不同功能:
客户端 / 功能 | 传输 | 一元 | 服务器端流式 | 客户端 & 双向流式 |
---|---|---|---|---|
Improbable | Fetch/XHR ️ | ✔️ | ✔️ | ❌19 |
Google (grpcwebtext ) | XHR ️ | ✔️ | ✔️ | ❌ |
Google (grpcweb ) | XHR ️ | ✔️ | ❌20 | ❌ |
有关此表的更多信息,请参阅 我在 GitHub 上的兼容性测试仓库。
兼容性测试未来可能会发展成为某种自动化测试框架,以强制执行和记录各种兼容性。
兼容性问题
当然,两种不同的代理也带来了兼容性问题。幸运的是,这些问题最近已得到解决,因此您可以使用任一客户端与任一代理配合使用。
未来展望
Google 的实现已于 2018 年 10 月宣布 1.0 版本正式发布21,并发布了未来目标的路线图22,其中包括:
- 高效的类 JSON 消息编码
- 适用于 Node、Python、Java 等的进程内代理
- 与流行框架(React、Angular、Vue)集成
- 支持 Fetch API 传输以实现内存高效流式传输
- 支持双向流式传输
Google 正在征求关于哪些功能对社区重要的反馈,因此如果您认为其中任何一项对您特别有价值,请填写他们的调查问卷23。
这两个项目最近的讨论已同意将 Google 客户端和 Envoy 代理作为新用户的首选解决方案。Improbable 客户端和代理将继续作为不依赖 Google Closure 的替代实现,但应被视为实验性的。将为现有用户提供迁移指南,以迁移到 Google 客户端,并且团队正在合作以统一生成的 API。
结论
Google 客户端将继续以稳定的速度实现新功能和修复,有一个专门的团队致力于其成功,并且它将是官方的 gRPC 客户端。它不像 Improbable 客户端那样支持 Fetch API,但如果这对社区来说是一个重要功能,将会添加。Google 团队和更广泛的社区正在合作开发官方客户端,以造福整个 gRPC 社区。自 GA(正式发布)宣布以来,社区对 Google gRPC-Web 仓库的贡献显著增加。
在选择这两个代理时,功能上没有区别,因此这取决于您的部署模型。Envoy 适用于某些场景,而进程内 Go 代理则有其自身的优势。
如果您今天开始使用 gRPC-Web,请首先尝试 Google 客户端。它具有严格的 API 兼容性保证,并建立在 Gmail 和 Google 地图所使用的坚如磐石的 Google Closure library 基础上。如果您需要 Fetch API 的内存效率或实验性的 WebSocket 客户端和双向流式传输,Improbable 客户端是一个不错的选择,并且在可预见的未来,Improbable 将继续使用和维护它。
无论如何,gRPC-Web 都是网络开发者的绝佳选择。它将一个复杂协议的可移植性、性能和工程优势带入了浏览器,这标志着前端开发者迎来了一个激动人心的时代!
参考资料
- improbable.io/games/blog/grpc-web-moving-past-restjson-towards-type-safe-web-apis ↩
- github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md ↩
- github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md ↩
- github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2 ↩
- github.com/improbable-eng/grpc-web ↩
- github.com/grpc/grpc-web ↩
- github.com/improbable-eng/grpc-web/issues/162 ↩
- github.com/grpc/grpc-web/issues/91 ↩
- github.com/improbable-eng/grpc-web/tree/master/client/grpc-web ↩
- npmjs.com/package/@improbable-eng/grpc-web ↩
- github.com/improbable-eng/grpc-web/tree/master/go/grpcweb ↩
- github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy ↩
- github.com/grpc/grpc-web/tree/master/javascript/net/grpc/web ↩
- developers.google.com/closure ↩
- npmjs.com/package/grpc-web ↩
- github.com/grpc/grpc-web/tree/master/net/grpc/gateway ↩
- envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_web_filter ↩
- streams.spec.whatwg.org ↩
- Improbable 客户端支持带有实验性 WebSocket 传输的客户端流式和双向流式。这不属于 gRPC-Web 规范的一部分,不建议用于生产环境。 ↩
-
grpcweb
允许调用服务器流式方法,但在流关闭之前它不会返回数据。 ↩ - gRPC-Web 正式发布 ↩
- github.com/grpc/grpc-web/blob/master/doc/roadmap.md ↩
- docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM ↩