RSS

gRPC 在浏览器中的现状

gRPC 1.0 于 2016 年 8 月发布,自那时以来,已成长为应用通信领域的首要技术解决方案之一。全球的初创公司、企业和开源项目都采用了它。它对多语言环境的支持、对性能、类型安全和开发者生产力的关注,已经改变了开发者设计架构的方式。

到目前为止,其优势主要局限于移动应用和后端开发者,而前端开发者则不得不继续依赖 JSON REST 接口作为主要信息交换手段。然而,随着 gRPC-Web 的发布,gRPC 有望成为前端开发者工具箱中的一个宝贵补充。

在这篇文章中,我将介绍一些 gRPC 在浏览器中的历史,探讨当前的现状,并分享一些对未来的看法。

开端

2016 年夏天,Google 的一个团队和 Improbable 的团队1都独立地开始着手实现可称为“浏览器版 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 服务器前放置一个小型代理,将请求和响应转换为浏览器可用的格式。

The role of the gRPC-Web proxy

两种实现

Google 和 Improbable 的团队都继续在两个不同的代码库5,6中实现了该规范,且实现方式略有不同,以至于两者都没有完全符合规范,并且长期以来,两者都不兼容对方的代理7,8

Improbable 的 gRPC-Web 客户端9使用 TypeScript 实现,并在 npm 上以 @improbable-eng/grpc-web10 的名称提供。还有一个可用的 Go 代理,它可以作为一个包导入到现有的 Go gRPC 服务器11中,也可以作为一个独立的代理,用于将任意 gRPC 服务器暴露给 gRPC-Web 前端12

Google 的 gRPC-Web 客户端13使用基于 Google Closure library14 的 JavaScript 实现。它在 npm 上以 grpc-web15 的名称提供。它最初附带了一个实现为 NGINX 扩展16的代理,但此后重心转移到 Envoy 代理 HTTP 过滤器17上,该过滤器在 v1.4.0 及更高版本中可用。

功能集

所有 gRPC HTTP/2 实现都支持四种方法类型:一元、服务器端流式、客户端流式和双向流式。然而,gRPC-Web 规范并未明确要求支持任何客户端或双向流式,只说明一旦浏览器实现了 WHATWG Streams18,就会实现这些功能。

Google 客户端支持一元和服务器端流式,但仅在使用 grpcwebtext 模式时支持。在 grpcweb 模式下,仅完全支持一元请求。这两种模式规定了在请求和响应中编码 protobuf 载荷的不同方式。

Improbable 客户端支持一元和服务器端流式,并有一个根据浏览器能力自动选择 XHR 或 Fetch 的实现。

下表总结了支持的不同功能

客户端 / 功能传输方式一元服务器端流式客户端 & 双向流式
ImprobableFetch/XHR ️✔️✔️19
Google (grpcwebtext)XHR ️✔️✔️
Google (grpcweb)XHR ️✔️20

有关此表的更多信息,请参阅我在 GitHub 上的兼容性测试仓库

这些兼容性测试未来可能会发展成为一个自动化测试框架,用于强制执行和记录各种兼容性。

兼容性问题

当然,存在两种不同的代理也带来了兼容性问题。幸运的是,这些问题最近已经解决,因此您可以预期使用任何一个客户端与任何一个代理。

未来

Google 实现于 2018 年 10 月宣布发布 1.0 版本并正式可用(GA)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 对于 Web 开发者来说都是一个优秀的选择。它将一个复杂协议的可移植性、性能和工程优势带入了浏览器,标志着前端开发者迎来了一个激动人心的时刻!

参考资料

  1. improbable.io/games/blog/grpc-web-moving-past-restjson-towards-type-safe-web-apis
  2. github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
  3. github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
  4. github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2
  5. github.com/improbable-eng/grpc-web
  6. github.com/grpc/grpc-web
  7. github.com/improbable-eng/grpc-web/issues/162
  8. github.com/grpc/grpc-web/issues/91
  9. github.com/improbable-eng/grpc-web/tree/master/client/grpc-web
  10. npmjs.com/package/@improbable-eng/grpc-web
  11. github.com/improbable-eng/grpc-web/tree/master/go/grpcweb
  12. github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy
  13. github.com/grpc/grpc-web/tree/master/javascript/net/grpc/web
  14. developers.google.com/closure
  15. npmjs.com/package/grpc-web
  16. github.com/grpc/grpc-web/tree/master/net/grpc/gateway
  17. envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_web_filter
  18. streams.spec.whatwg.org
  19. Improbable 客户端支持带实验性 websocket 传输的客户端和双向流式。这不属于 gRPC-Web 规范,不推荐用于生产环境。
  20. grpcweb 允许调用服务器流式方法,但在流关闭之前不会返回数据。
  21. gRPC-Web 正式发布
  22. github.com/grpc/grpc-web/blob/master/doc/roadmap.md
  23. docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM