gRPC-Web 全面可用
我们很高兴地宣布 gRPC-Web 的 GA (正式发布) 版本发布,它是一个 JavaScript 客户端库,使 Web 应用程序能够直接与 gRPC 后端服务通信,而无需 HTTP 服务器充当中间层。“GA”意味着 gRPC-Web 现已正式发布,稳定且可用于生产环境。
借助 gRPC-Web,您现在可以通过使用 Protocol Buffers 定义客户端和服务器端数据类型及服务接口,轻松构建真正的端到端 gRPC 应用程序架构。长期以来,这是一项备受期待的功能,我们很高兴地宣布它现在已可用于生产环境。此外,能够访问 gRPC 服务为围绕 gRPC 的基于 Web 的工具开辟了新的激动人心的可能性。
基础知识
gRPC-Web 就像 gRPC 一样,允许您使用 Protocol Buffers 定义客户端 (Web) 和后端 gRPC 服务之间的服务“契约”。客户端可以随后自动生成。为此,您可以在 Closure 编译器或更广泛使用的 CommonJS 之间进行选择。这种开发过程消除了管理诸如创建自定义 JSON 序列化和反序列化逻辑、处理 HTTP 状态码(在不同的 REST API 中可能有所不同)、管理内容类型协商等问题的需要。
从更广阔的架构层面来看,gRPC-Web 实现了端到端 gRPC。下图对此进行了说明


图 1. 使用 gRPC-Web 的 gRPC(左)和使用 REST 的 gRPC(右)
在左侧的 gRPC-Web 体系中,客户端应用程序使用 Protocol Buffers 与 gRPC 后端服务器通信,该后端服务器再使用 Protocol Buffers 与其他 gRPC 后端服务通信。在右侧的 REST 体系中,Web 应用程序使用 HTTP 与后端 REST API 服务器通信,然后该服务器再使用 Protocol Buffers 与后端服务通信。
使用 gRPC-Web 的优势
gRPC-Web 将随着时间的推移提供更广泛的功能集,但以下是 1.0 版本目前包含的功能:
- 端到端 gRPC — 使您能够使用 Protocol Buffers 构建整个 RPC 管道。设想这样一个场景:客户端请求发送到 HTTP 服务器,然后该服务器与 5 个后端 gRPC 服务交互。很有可能您在构建 HTTP 交互层上花费的时间,将与构建整个管道其余部分的时间一样多。
- 前端和后端团队之间更紧密的协调 — 整个 RPC 管道都使用 Protocol Buffers 定义后,您不再需要将“微服务团队”与“客户端团队”分开。客户端与后端交互只是众多 gRPC 层中的又一层。
- 轻松生成客户端库 — 借助 gRPC-Web,与“外部”世界交互的服务器,即连接您的后端堆栈到互联网的“膜”,现在是 gRPC 服务器而不是 HTTP 服务器,这意味着您服务的所有客户端库都可以是 gRPC 库。需要 Ruby、Python、Java 和其他 4 种语言的客户端库?您不再需要为所有这些语言编写 HTTP 客户端。
gRPC-Web 示例
上一节阐述了 gRPC-Web 在大型应用程序中的一些高级优势。现在,让我们通过一个示例更深入地探讨:一个简单的待办事项应用。在 gRPC-Web 中,您可以从一个简单的 todos.proto
定义开始,如下所示:
syntax = "proto3";
package todos;
message Todo {
string content = 1;
bool finished = 2;
}
message GetTodoRequest {
int32 id = 1;
}
service TodoService {
rpc GetTodoById (GetTodoRequest) returns (Todo);
}
CommonJS 客户端代码可以从这个 .proto
定义生成,使用以下命令:
protoc echo.proto \
--js_out=import_style=commonjs:./output \
--grpc-web_out=import_style=commonjs:./output
现在,从后端 gRPC 服务获取待办事项列表就像这样简单:
const {GetTodoRequest} = require('./todos_pb.js');
const {TodoServiceClient} = require('./todos_grpc_web_pb.js');
const todoService = new proto.todos.TodoServiceClient('https://:8080');
const todoId = 1234;
var getTodoRequest = new proto.todos.GetTodoRequest();
getTodoRequest.setId(todoId);
var metadata = {};
var getTodo = todoService.getTodoById(getTodoRequest, metadata, (err, response) => {
if (err) {
console.log(err);
} else {
const todo = response.todo();
if (todo == null) {
console.log(`A TODO with the ID ${todoId} wasn't found`);
} else {
console.log(`Fetched TODO with ID ${todoId}: ${todo.content()}`);
}
}
});
一旦您声明了数据类型和服务接口,gRPC-Web 就会抽象化所有样板代码,为您留下一个清晰且人性化的 API(本质上与当前 Node.js 的 gRPC API 相同,只是转移到了客户端)。
在后端,gRPC 服务器可以使用任何支持 gRPC 的语言编写,例如 Go、Java、C++、Ruby、Node.js 等。最后的关键部分是服务代理。从一开始,gRPC-Web 将支持 Envoy 作为默认服务代理,它具有内置的 envoy.grpc_web 过滤器,您只需几行配置即可应用。
后续步骤
正式发布(GA)意味着核心构建模块已稳固就位,可用于生产 Web 应用程序。但 gRPC-Web 的未来还有更多内容。请查看官方路线图,了解核心团队对近期未来的设想。
如果您有兴趣为 gRPC-Web 做出贡献,我们很乐意得到社区的帮助,具体如下:
前端框架集成 — 常用前端框架如 React、Vue 和 Angular 尚未提供对 gRPC-Web 的官方支持。但我们非常希望看到这些框架能够支持 gRPC-Web,因为这些前端框架与 gRPC-Web 之间的集成可以为应用程序带来用户可感知的性能优势。如果您有兴趣为这些前端框架构建支持,请在 gRPC.io 邮件列表、GitHub 上提交功能请求或通过下面的功能调查表告知我们。
特定语言的代理支持 — 截至 GA 发布,Envoy 是 gRPC-Web 的默认代理,通过特殊模块提供支持。NGINX 也受支持。但我们也希望看到针对特定语言的进程内代理的开发,因为它们消除了对特殊代理(如 Envoy 和 NGINX)的需求,并将使 gRPC-Web 的使用变得更加容易。
我们也非常欢迎社区提出功能请求。目前,提出功能请求的最佳方式是填写gRPC-Web 路线图功能调查。填写表格时,请列出您希望看到的功能,并在我希望贡献部分告知我们您是否希望为这些功能的开发做出贡献。gRPC-Web 工程师将在项目开发过程中认真对待这些信息。
最重要的是,我们感谢所有 Alpha 和 Beta 用户,他们在过去一年中为我们提供了反馈、错误报告和拉取请求贡献。我们当然希望保持这种势头,并确保该项目为开发者社区带来切实的利益。